From 8c47e146342197730364ae786391518faba5623d Mon Sep 17 00:00:00 2001 From: freedomadnetworkdev Date: Tue, 20 Aug 2024 14:22:53 -0400 Subject: [PATCH 01/15] Create fanAdapter.md --- modules/fanAdapter.md | 40 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) create mode 100644 modules/fanAdapter.md diff --git a/modules/fanAdapter.md b/modules/fanAdapter.md new file mode 100644 index 00000000000..caa18ca8552 --- /dev/null +++ b/modules/fanAdapter.md @@ -0,0 +1,40 @@ +# Freedom Ad Network Bidder Adapter + +# Overview + +``` +Module Name: Freedom Ad Network Bidder Adapter +Module Type: Bidder Adapter +Maintainer: info@freedomadnetwork.com +``` + +## Description + +Module that connects to FAN's demand sources. + +## Bid Parameters + +| Name | Scope | Type | Description | Example | +|---------------|----------|--------------------|-----------------------------------------|-------------------------------------------------| +| `placementId` | required | String | The Placement Id provided by FAN. | `e6203f1e-bd6d-4f42-9895-d1a19cdb83c8` | + +## Example + +### Banner Ads + +```javascript +var adUnits = [{ + code: 'banner-ad-div', + mediaTypes: { + banner: { + sizes: [[300, 250]] + } + }, + bids: [{ + bidder: 'freedomadnetwork', + params: { + placementId: 'e6203f1e-bd6d-4f42-9895-d1a19cdb83c8' + } + }] +}]; +``` From 622e39c584be504af66db055127e98dbf39f77a0 Mon Sep 17 00:00:00 2001 From: freedomadnetworkdev Date: Tue, 20 Aug 2024 14:23:08 -0400 Subject: [PATCH 02/15] Create fanAdapter.js --- modules/fanAdapter.js | 383 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 383 insertions(+) create mode 100644 modules/fanAdapter.js diff --git a/modules/fanAdapter.js b/modules/fanAdapter.js new file mode 100644 index 00000000000..ab413cb9cc6 --- /dev/null +++ b/modules/fanAdapter.js @@ -0,0 +1,383 @@ +import * as utils from '../src/utils.js'; +import MD5 from 'crypto-js/md5.js'; +import { ajax } from '../src/ajax.js'; +import { BANNER, VIDEO, NATIVE } from '../src/mediaTypes.js'; +import { config } from '../src/config'; +import { getGlobal } from '../src/prebidGlobal.js'; +import { registerBidder } from '../src/adapters/bidderFactory'; +const BIDDER_CODE = 'freedomadnetwork'; +const BASE_URL = 'https://srv.freedomadnetwork.com'; + +/** + * Get user id from bid request. if no user id module used, return a new uuid. + * + * @param {BidRequest} bidRequest + * @returns {String} userId + */ +function getUserId(bidRequest) { + return generateUserId(); +} + +/** + * Get browser language + * + * @returns {String} language + */ +function getLanguage() { + const lang = (navigator.languages && navigator.languages[0]) || + navigator.language || navigator.userLanguage; + return lang ? lang.split('-')[0] : DEFAULT_LANGUAGE; +} + +/** + * Get device info + * + * @returns {Object} + */ +function getDevice() { + const device = config.getConfig('device') || {}; + + device.w = device.w || window.screen.width; + device.h = device.h || window.screen.height; + device.ua = device.ua || navigator.userAgent; + device.language = device.language || getLanguage(); + device.dnt = typeof device.dnt === 'number' + ? device.dnt : (utils.getDNT() ? 1 : 0); + + return device; +} + +/** + * Build OpenRTB request from bidRequest and bidderRequest + * + * @param {BidRequest} bidRequest + * @param {BidderRequest} bidderRequest + * @returns {Request} + */ +function buildBidRequest(bid, bidderRequest) { + const userId = getUserId(bid); + + const payload = { + id: bid.bidId, + tmax: bidderRequest.timeout, + placements: [bid.params.placementId], + test: config.getConfig('debug') ? 1 : 0, + device: getDevice(), + at: 2, + user: { + coppa: config.getConfig('coppa') ? 1 : 0, + id: userId, + } + } + + const gdprConsent = utils.deepAccess(bidderRequest, 'gdprConsent'); + if (!!gdprConsent && gdprConsent.gdprApplies) { + payload.user.gdpr = 1; + payload.user.consent = gdprConsent.consentString; + } + + const uspConsent = utils.deepAccess(bidderRequest, 'uspConsent'); + if (uspConsent) { + payload.user.usp = uspConsent; + } + + return { + method: 'POST', + url: BASE_URL + '/pb/req', + data: JSON.stringify(payload), + options: { + contentType: 'application/json', + withCredentials: false, + customHeaders: { + 'Accept-Language': 'en;q=10', + 'Authorization': 'Bearer ' + userId + }, + }, + originalBidRequest: bid + } +} + +/** + * Generate stable viewport hash + * + * @returns {String} viewportHash + */ +function viewportHash() { + var canvas = document.createElement('canvas'); + var gl = + canvas.getContext('webgl') ?? canvas.getContext('experimental-webgl'); + var hash = []; + + if (gl && gl.getExtension) { + gl.ge = gl.getExtension; + gl.gs = gl.getShaderPrecisionFormat; + gl.gp = gl.getParameter; + + var debugInfo = gl.ge('WEBGL_debug_renderer_info'); + var drawBuffers = gl.ge('WEBGL_draw_buffers'); + var anisotropy = + gl.ge('EXT_texture_filter_anisotropic') || + gl.ge('WEBKIT_EXT_texture_filter_anisotropic') || + gl.ge('MOZ_EXT_texture_filter_anisotropic'); + var vertex = [ + gl.gs(gl.VERTEX_SHADER, gl.HIGH_FLOAT), + gl.gs(gl.VERTEX_SHADER, gl.MEDIUM_FLOAT), + gl.gs(gl.VERTEX_SHADER, gl.LOW_FLOAT), + ]; + var frag = [ + gl.gs(gl.FRAGMENT_SHADER, gl.HIGH_FLOAT), + gl.gs(gl.FRAGMENT_SHADER, gl.MEDIUM_FLOAT), + gl.gs(gl.FRAGMENT_SHADER, gl.LOW_FLOAT), + ]; + + window.evg = debugInfo + ? gl.gp(debugInfo.UNMASKED_RENDERER_WEBGL) + : gl.gp(gl.RENDERER); + + hash = [ + vertex, + frag, + gl.getContextAttributes().antialias, + gl.gp(gl.VERSION), + gl.gp(gl.SHADING_LANGUAGE_VERSION), + gl.gp(gl.VENDOR), + gl.gp(gl.ALIASED_LINE_WIDTH_RANGE), + gl.gp(gl.RED_BITS), + gl.gp(gl.GREEN_BITS), + gl.gp(gl.BLUE_BITS), + gl.gp(gl.ALPHA_BITS), + gl.gp(gl.DEPTH_BITS), + gl.gp(gl.STENCIL_BITS), + gl.gp(gl.MAX_RENDERBUFFER_SIZE), + gl.gp(gl.MAX_COMBINED_TEXTURE_IMAGE_UNITS), + gl.gp(gl.MAX_CUBE_MAP_TEXTURE_SIZE), + gl.gp(gl.MAX_FRAGMENT_UNIFORM_VECTORS), + gl.gp(gl.MAX_TEXTURE_IMAGE_UNITS), + gl.gp(gl.MAX_TEXTURE_SIZE), + gl.gp(gl.MAX_VARYING_VECTORS), + gl.gp(gl.MAX_VERTEX_ATTRIBS), + gl.gp(gl.MAX_VERTEX_TEXTURE_IMAGE_UNITS), + gl.gp(gl.MAX_VERTEX_UNIFORM_VECTORS), + gl.gp(gl.ALIASED_LINE_WIDTH_RANGE), + gl.gp(gl.ALIASED_POINT_SIZE_RANGE), + gl.gp(gl.MAX_VIEWPORT_DIMS), + gl.gs(gl.FRAGMENT_SHADER, gl.HIGH_INT), + gl.getSupportedExtensions(), + debugInfo ? gl.gp(debugInfo.UNMASKED_RENDERER_WEBGL) : gl.gp(gl.RENDERER), + drawBuffers ? gl.gp(drawBuffers.MAX_DRAW_BUFFERS_WEBGL) : 1, + anisotropy ? gl.gp(anisotropy.MAX_TEXTURE_MAX_ANISOTROPY_EXT) : 0, + ]; + } + + return MD5(JSON.stringify(hash)).toString(); +} + +/** + * Generate stable user id + * + * @returns {String} userId + */ +function generateUserId() { + var flavors = [ + // Blink and some browsers on iOS + 'chrome', + + // Safari on macOS + 'safari', + + // Chrome on iOS (checked in 85 on 13 and 87 on 14) + '__crWeb', + '__gCrWeb', + + // Yandex Browser on iOS, macOS and Android (checked in 21.2 on iOS 14, macOS and Android) + 'yandex', + + // Yandex Browser on iOS (checked in 21.2 on 14) + '__yb', + '__ybro', + + // Firefox on iOS (checked in 32 on 14) + '__firefox__', + + // Edge on iOS (checked in 46 on 14) + '__edgeTrackingPreventionStatistics', + 'webkit', + + // Opera Touch on iOS (checked in 2.6 on 14) + 'oprt', + + // Samsung Internet on Android (checked in 11.1) + 'samsungAr', + + // UC Browser on Android (checked in 12.10 and 13.0) + 'ucweb', + 'UCShellJava', + + // Puffin on Android (checked in 9.0) + 'puffinDevice', + ]; + + var flavor = null; + for (var i = 0; i < flavors.length; i++) { + if (window[flavors[i]] && typeof window[flavors[i]] === 'object') { + flavor = flavors[i]; + } + } + + var screen = [ + parseInt(window.screen.width), + parseInt(window.screen.height), + window.screen.availHeight, + window.screen.availWidth, + ]; + + var hash = [ + viewportHash(), + flavor, + navigator.webdriver, + navigator.language || + navigator.userLanguage || + navigator.browserLanguage || + navigator.systemLanguage || + null, + navigator.userAgent, + window.screen.colorDepth, + navigator.doNotTrack || navigator.msDoNotTrack || window.doNotTrack || null, + navigator.maxTouchPoints || navigator.msMaxTouchPoints || null, + navigator.vendor, + navigator.cpuClass, + navigator.oscpu, + navigator.deviceMemory, + navigator.hardwareConcurrency, + navigator.languages, + navigator.pdfViewerEnabled, + navigator.plugins, + window.chrome ? screen : null, + window.matchMedia('(color-gamut: rec2020)').matches, + window.matchMedia('(color-gamut: p3)').matches, + window.matchMedia('(color-gamut: srgb)').matches, + window.matchMedia('(prefers-contrast: no-preference)').matches, + window.matchMedia('(prefers-contrast: more)').matches, + window.matchMedia('(prefers-contrast: less)').matches, + window.matchMedia('(prefers-contrast: custom)').matches, + window.matchMedia('(inverted-colors: inverted)').matches, + window.matchMedia('(prefers-reduced-motion: reduce)').matches, + ]; + + hash = MD5(JSON.stringify(hash)).toString(); + + return hash; +} + +export const spec = { + code: BIDDER_CODE, + isBidRequestValid: function(bid) { + if (!bid) { + utils.logWarn(BIDDER_CODE, 'Invalid bid', bid); + + return false; + } + + if (!bid.params) { + utils.logWarn(BIDDER_CODE, 'bid.params is required'); + + return false; + } + + if (!bid.params.placementId) { + utils.logWarn(BIDDER_CODE, 'bid.params.placementId is required'); + + return false; + } + + var banner = utils.deepAccess(bid, 'mediaTypes.banner'); + if (banner === undefined) { + return false; + } + + return true; + }, + + buildRequests: function(validBidRequests, bidderRequest) { + return validBidRequests.map(bid => buildBidRequest(bid, bidderRequest)); + }, + + /** + * Unpack the response from the server into a list of bids. + * + * @param {ServerResponse} serverResponse A successful response from the server. + * @return {Bid[]} An array of bids which were nested inside the server. + */ + interpretResponse: function (serverResponse, bidRequest) { + const serverBody = serverResponse.body; + let bidResponses = []; + + serverBody.forEach((response) => { + const bidResponse = { + requestId: response.id, + bidid: response.bidid, + impid: response.impid, + userId: response.userId, + cpm: response.cpm, + currency: response.currency, + width: response.width, + height: response.height, + ad: response.payload, + ttl: response.ttl, + creativeId: response.crid, + netRevenue: response.netRevenue, + trackers: response.trackers, + meta: { + mediaType: response.mediaType, + advertiserDomains: response.domains, + } + }; + + bidResponses.push(bidResponse); + }); + + return bidResponses; + }, + + /** + * Register bidder specific code, which will execute if a bid from this bidder won the auction + * + * @param {Bid} bid The bid that won the auction + */ + onBidWon: function (bid) { + if (!bid) { + return; + } + + const payload = { + id: bid.bidid, + impid: bid.impid, + t: bid.cpm, + } + + ajax(BASE_URL + '/pb/imp', null, JSON.stringify(payload), { + method: 'POST', + customHeaders: { + 'Accept-Language': 'en;q=10', + 'Authorization': 'Bearer ' + bid.userId + }, + }); + + if (bid.trackers && bid.trackers.length > 0) { + for (var i = 0; i < bid.trackers.length; i++) { + if (bid.trackers[i].type == 0) { + utils.triggerPixel(bid.trackers[i].url); + } + } + } + }, + onSetTargeting: function(bid) {}, + onBidderError: function(error) { + console.log(error); + }, + getUserSyncs: function(syncOptions, serverResponses, gdprConsent, uspConsent) {}, + onTimeout: function(timeoutData) {}, + supportedMediaTypes: [BANNER, NATIVE] +} + +registerBidder(spec); From 9bbe5036fa4a4e6c529ef58e2da38fa1bc46d1df Mon Sep 17 00:00:00 2001 From: freedomadnetworkdev Date: Tue, 20 Aug 2024 14:23:54 -0400 Subject: [PATCH 03/15] Create fanAdapter_spec.js --- test/spec/modules/fanAdapter_spec.js | 332 +++++++++++++++++++++++++++ 1 file changed, 332 insertions(+) create mode 100644 test/spec/modules/fanAdapter_spec.js diff --git a/test/spec/modules/fanAdapter_spec.js b/test/spec/modules/fanAdapter_spec.js new file mode 100644 index 00000000000..6cb6ea5eaa8 --- /dev/null +++ b/test/spec/modules/fanAdapter_spec.js @@ -0,0 +1,332 @@ +import * as ajax from 'src/ajax.js'; +import { expect } from 'chai'; +import { spec } from 'modules/fanAdapter.js'; +import { newBidder } from 'src/adapters/bidderFactory.js'; +import { BANNER, NATIVE, VIDEO } from 'src/mediaTypes.js'; + +describe('Freedom Ad Network Bid Adapter', function () { + describe('Test isBidRequestValid', function () { + it('undefined bid should return false', function () { + expect(spec.isBidRequestValid()).to.be.false; + }); + + it('null bid should return false', function () { + expect(spec.isBidRequestValid(null)).to.be.false; + }); + + it('bid.params should be set', function () { + expect(spec.isBidRequestValid({})).to.be.false; + }); + + it('bid.params.placementId should be set', function () { + expect(spec.isBidRequestValid({ + params: { foo: 'bar' } + })).to.be.false; + }); + + it('valid bid should return true', function () { + expect(spec.isBidRequestValid({ + params: { placementId: 'e6203f1e-bd6d-4f42-9895-d1a19cdb83c8' } + })).to.be.true; + }); + }); + + describe('Test buildRequests', function () { + const bidderRequest = { + auctionId: 'b06c5141-fe8f-4cdf-9d7d-54415490a917', + auctionStart: Date.now(), + bidderCode: 'myBidderCode', + bidderRequestId: '15246a574e859f', + refererInfo: { + page: 'http://example.com', + stack: ['http://example.com'] + }, + gdprConsent: { + gdprApplies: true, + consentString: 'IwuyYwpjmnsauyYasIUWwe' + }, + uspConsent: 'Oush3@jmUw82has', + timeout: 3000 + }; + + it('build request object', function () { + const bidRequests = [ + { + adUnitCode: 'test-div', + auctionId: 'b06c5141-fe8f-4cdf-9d7d-54415490a917', + bidId: '8064026a1776', + bidder: 'freedomadnetwork', + bidderRequestId: '15246a574e859f', + mediaTypes: { + banner: { sizes: [[300, 250]] } + }, + params: { + placementId: 'e6203f1e-bd6d-4f42-9895-d1a19cdb83c8' + } + }, + { + adUnitCode: 'test-native', + auctionId: 'b06c5141-fe8f-4cdf-9d7d-54415490a917', + bidId: '8064026a1777', + bidder: 'freedomadnetwork', + bidderRequestId: '15246a574e859f', + mediaTypes: { + native: { + title: { + required: true, + len: 20, + }, + image: { + required: true, + sizes: [300, 250], + aspect_ratios: [{ + ratio_width: 1, + ratio_height: 1 + }] + }, + icon: { + required: true, + sizes: [60, 60], + aspect_ratios: [{ + ratio_width: 1, + ratio_height: 1 + }] + }, + sponsoredBy: { + required: true, + len: 20 + }, + body: { + required: true, + len: 140 + }, + cta: { + required: true, + len: 20, + } + } + }, + params: { + placementId: '3f50a79e-5582-4e5c-b1f4-9dcc1c82cece' + } + }, + { + adUnitCode: 'test-native2', + auctionId: 'b06c5141-fe8f-4cdf-9d7d-54415490a917', + bidId: '8064026a1778', + bidder: 'freedomadnetwork', + bidderRequestId: '15246a574e859f', + mediaTypes: { + native: { + title: {}, + image: {}, + icon: {}, + sponsoredBy: {}, + body: {}, + cta: {} + } + }, + params: { + placementId: '2015defc-19db-4cf6-926d-d2d0d32122fa', + } + }, + { + adUnitCode: 'test-native3', + auctionId: 'b06c5141-fe8f-4cdf-9d7d-54415490a917', + bidId: '8064026a1779', + bidder: 'freedomadnetwork', + bidderRequestId: '15246a574e859f', + mediaTypes: { + native: {}, + }, + params: { + placementId: '8064026a-9932-45ae-b804-03491302ad88' + } + } + ]; + + let reqs; + + expect(function () { + reqs = spec.buildRequests(bidRequests, bidderRequest); + }).to.not.throw(); + + expect(reqs).to.be.an('array').that.have.lengthOf(bidRequests.length); + + for (let i = 0, len = reqs.length; i < len; i++) { + const req = reqs[i]; + const bidRequest = bidRequests[i]; + + expect(req.method).to.equal('POST'); + expect(req.url).to.equal('https://srv.freedomadnetwork.com/pb/req'); + + expect(req.options).to.be.an('object'); + expect(req.options.contentType).to.contain('application/json'); + expect(req.options.customHeaders).to.be.an('object'); + expect(req.options.customHeaders['Authorization']).to.equal('Bearer 1d00c41fbf6bcf02b760c7f9e6266202'); + + expect(req.originalBidRequest).to.equal(bidRequest); + + expect(req.data).to.equal('{"id":"'+ bidRequest.bidId +'","tmax":3000,"placements":["'+ bidRequest.params.placementId +'"],"test":0,"device":{"w":800,"h":600,"ua":"Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) HeadlessChrome/125.0.6422.141 Safari/537.36","language":"en","dnt":0},"at":2,"user":{"coppa":0,"id":"1d00c41fbf6bcf02b760c7f9e6266202","gdpr":1,"consent":"IwuyYwpjmnsauyYasIUWwe","usp":"Oush3@jmUw82has"}}'); + } + }); + + it('random uid will be generate when userId is empty', function () { + const bidRequests = [{ + adUnitCode: 'test-div', + auctionId: 'b06c5141-fe8f-4cdf-9d7d-54415490a917', + bidId: '8064026a1776', + bidder: 'freedomadnetwork', + bidderRequestId: '15246a574e859f', + mediaTypes: { + banner: { sizes: [[300, 250]] } + }, + params: { + placementId: 'e6203f1e-bd6d-4f42-9895-d1a19cdb83c8' + } + }]; + + const reqs = spec.buildRequests(bidRequests, bidderRequest); + + let requestData; + expect(function () { + requestData = JSON.parse(reqs[0].data); + }).to.not.throw(); + + expect(requestData.user.id).to.not.be.empty; + }) + }); + + describe('Test adapter request', function () { + const adapter = newBidder(spec); + + it('adapter.callBids exists and is a function', function () { + expect(adapter.callBids).to.be.a('function'); + }); + }); + + describe('Test response interpretResponse', function () { + it('Test main interpretResponse', function () { + const serverResponse = { + body: [{ + id: '8064026a1776', + bidid: '78e10bd4-aa67-40a6-b282-0f2697251eb3', + impid: '88faf7e7-bef8-43a5-9ef3-73db10c2af6b', + userId: '944c9c880be09af1e90da1f883538607', + cpm: 17.76, + currency: 'USD', + width: 300, + height: 250, + ttl: 60, + netRevenue: false, + crid: '03f3ed6f-1a9e-4276-8ad7-0dc5efae289e', + payload: '', + trackers: [], + mediaType: 'native', + domains: ['foo.com'], + }] + }; + + const bidResponses = spec.interpretResponse(serverResponse, { + originalBidRequest: { + adUnitCode: 'test-div', + auctionId: 'b06c5141-fe8f-4cdf-9d7d-54415490a917', + bidId: '8064026a1776', + bidder: 'freedomadnetwork', + bidderRequestId: '15246a574e859f', + mediaTypes: { + banner: { sizes: [[300, 250]] } + }, + params: { + placementId: 'e6203f1e-bd6d-4f42-9895-d1a19cdb83c8' + } + } + }); + + expect(bidResponses).to.be.an('array').that.is.not.empty; + + const bid = serverResponse.body[0]; + const bidResponse = bidResponses[0]; + + expect(bidResponse.requestId).to.equal(bid.id); + expect(bidResponse.bidid).to.equal(bid.bidid); + expect(bidResponse.impid).to.equal(bid.impid); + expect(bidResponse.userId).to.equal(bid.userId); + expect(bidResponse.cpm).to.equal(bid.cpm); + expect(bidResponse.currency).to.equal(bid.currency); + expect(bidResponse.width).to.equal(bid.width); + expect(bidResponse.height).to.equal(bid.height); + expect(bidResponse.ad).to.equal(bid.payload); + expect(bidResponse.ttl).to.equal(bid.ttl); + expect(bidResponse.creativeId).to.equal(bid.crid); + expect(bidResponse.netRevenue).to.equal(bid.netRevenue); + expect(bidResponse.trackers).to.equal(bid.trackers); + expect(bidResponse.meta.mediaType).to.equal(bid.mediaType); + expect(bidResponse.meta.advertiserDomains).to.equal(bid.domains); + }); + + it('Test empty server response', function () { + const bidResponses = spec.interpretResponse({}, {}); + + expect(bidResponses).to.be.an('array').that.is.empty; + }); + + it('Test empty bid response', function () { + const bidResponses = spec.interpretResponse({ body: [] }, {}); + + expect(bidResponses).to.be.an('array').that.is.empty; + }); + }); + + describe('Test getUserSyncs', function () { + it('getUserSyncs should return empty', function () { + const serverResponse = {}; + const syncOptions = {} + const userSyncPixels = spec.getUserSyncs(syncOptions, [serverResponse]) + expect(userSyncPixels).to.have.lengthOf(0); + }); + }); + + describe('Test onTimeout', function () { + it('onTimeout should not throw', function () { + expect(spec.onTimeout()).to.not.throw; + }); + }); + + describe('Test onBidWon', function () { + let sandbox, ajaxStub; + + beforeEach(function () { + sandbox = sinon.sandbox.create(); + ajaxStub = sandbox.stub(ajax, 'ajax'); + }); + + afterEach(function () { + sandbox.restore(); + ajaxStub.restore(); + }); + + const bid = { + bidid: '78e10bd4-aa67-40a6-b282-0f2697251eb3', + impid: '88faf7e7-bef8-43a5-9ef3-73db10c2af6b', + cpm: 17.76, + trackers: ['foo.com'], + } + + it('onBidWon empty bid should not throw', function () { + expect(spec.onBidWon({})).to.not.throw; + expect(ajaxStub.calledOnce).to.equal(false); + }); + + it('onBidWon valid bid should not throw', function () { + expect(spec.onBidWon(bid)).to.not.throw; + expect(ajaxStub.calledOnce).to.equal(true); + }); + }); + + describe('Test onSetTargeting', function () { + it('onSetTargeting should not throw', function () { + expect(spec.onSetTargeting()).to.not.throw; + }); + }); +}); From 475a4d0e0e1c661a04e520c503caf6e788af2d12 Mon Sep 17 00:00:00 2001 From: freedomadnetworkdev Date: Tue, 20 Aug 2024 14:36:15 -0400 Subject: [PATCH 04/15] Update fanAdapter_spec.js --- test/spec/modules/fanAdapter_spec.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/spec/modules/fanAdapter_spec.js b/test/spec/modules/fanAdapter_spec.js index 6cb6ea5eaa8..97abe82c8ad 100644 --- a/test/spec/modules/fanAdapter_spec.js +++ b/test/spec/modules/fanAdapter_spec.js @@ -167,7 +167,7 @@ describe('Freedom Ad Network Bid Adapter', function () { expect(req.originalBidRequest).to.equal(bidRequest); - expect(req.data).to.equal('{"id":"'+ bidRequest.bidId +'","tmax":3000,"placements":["'+ bidRequest.params.placementId +'"],"test":0,"device":{"w":800,"h":600,"ua":"Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) HeadlessChrome/125.0.6422.141 Safari/537.36","language":"en","dnt":0},"at":2,"user":{"coppa":0,"id":"1d00c41fbf6bcf02b760c7f9e6266202","gdpr":1,"consent":"IwuyYwpjmnsauyYasIUWwe","usp":"Oush3@jmUw82has"}}'); + expect(req.data).to.equal('{"id":"' + bidRequest.bidId + '","tmax":3000,"placements":["' + bidRequest.params.placementId + '"],"test":0,"device":{"w":800,"h":600,"ua":"Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) HeadlessChrome/125.0.6422.141 Safari/537.36","language":"en","dnt":0},"at":2,"user":{"coppa":0,"id":"1d00c41fbf6bcf02b760c7f9e6266202","gdpr":1,"consent":"IwuyYwpjmnsauyYasIUWwe","usp":"Oush3@jmUw82has"}}'); } }); From d82ba03c49ea6581742ce1f617da16b0342b5337 Mon Sep 17 00:00:00 2001 From: freedomadnetworkdev Date: Tue, 20 Aug 2024 14:47:52 -0400 Subject: [PATCH 05/15] Update fanAdapter.js --- modules/fanAdapter.js | 174 ++---------------------------------------- 1 file changed, 6 insertions(+), 168 deletions(-) diff --git a/modules/fanAdapter.js b/modules/fanAdapter.js index ab413cb9cc6..0b8f3c517fa 100644 --- a/modules/fanAdapter.js +++ b/modules/fanAdapter.js @@ -1,10 +1,9 @@ import * as utils from '../src/utils.js'; import MD5 from 'crypto-js/md5.js'; import { ajax } from '../src/ajax.js'; -import { BANNER, VIDEO, NATIVE } from '../src/mediaTypes.js'; -import { config } from '../src/config'; -import { getGlobal } from '../src/prebidGlobal.js'; -import { registerBidder } from '../src/adapters/bidderFactory'; +import { BANNER, NATIVE } from '../src/mediaTypes.js'; +import { config } from '../src/config.js'; +import { registerBidder } from '../src/adapters/bidderFactory.js'; const BIDDER_CODE = 'freedomadnetwork'; const BASE_URL = 'https://srv.freedomadnetwork.com'; @@ -26,7 +25,7 @@ function getUserId(bidRequest) { function getLanguage() { const lang = (navigator.languages && navigator.languages[0]) || navigator.language || navigator.userLanguage; - return lang ? lang.split('-')[0] : DEFAULT_LANGUAGE; + return lang ? lang.split('-')[0] : 'en'; } /** @@ -97,174 +96,13 @@ function buildBidRequest(bid, bidderRequest) { } } -/** - * Generate stable viewport hash - * - * @returns {String} viewportHash - */ -function viewportHash() { - var canvas = document.createElement('canvas'); - var gl = - canvas.getContext('webgl') ?? canvas.getContext('experimental-webgl'); - var hash = []; - - if (gl && gl.getExtension) { - gl.ge = gl.getExtension; - gl.gs = gl.getShaderPrecisionFormat; - gl.gp = gl.getParameter; - - var debugInfo = gl.ge('WEBGL_debug_renderer_info'); - var drawBuffers = gl.ge('WEBGL_draw_buffers'); - var anisotropy = - gl.ge('EXT_texture_filter_anisotropic') || - gl.ge('WEBKIT_EXT_texture_filter_anisotropic') || - gl.ge('MOZ_EXT_texture_filter_anisotropic'); - var vertex = [ - gl.gs(gl.VERTEX_SHADER, gl.HIGH_FLOAT), - gl.gs(gl.VERTEX_SHADER, gl.MEDIUM_FLOAT), - gl.gs(gl.VERTEX_SHADER, gl.LOW_FLOAT), - ]; - var frag = [ - gl.gs(gl.FRAGMENT_SHADER, gl.HIGH_FLOAT), - gl.gs(gl.FRAGMENT_SHADER, gl.MEDIUM_FLOAT), - gl.gs(gl.FRAGMENT_SHADER, gl.LOW_FLOAT), - ]; - - window.evg = debugInfo - ? gl.gp(debugInfo.UNMASKED_RENDERER_WEBGL) - : gl.gp(gl.RENDERER); - - hash = [ - vertex, - frag, - gl.getContextAttributes().antialias, - gl.gp(gl.VERSION), - gl.gp(gl.SHADING_LANGUAGE_VERSION), - gl.gp(gl.VENDOR), - gl.gp(gl.ALIASED_LINE_WIDTH_RANGE), - gl.gp(gl.RED_BITS), - gl.gp(gl.GREEN_BITS), - gl.gp(gl.BLUE_BITS), - gl.gp(gl.ALPHA_BITS), - gl.gp(gl.DEPTH_BITS), - gl.gp(gl.STENCIL_BITS), - gl.gp(gl.MAX_RENDERBUFFER_SIZE), - gl.gp(gl.MAX_COMBINED_TEXTURE_IMAGE_UNITS), - gl.gp(gl.MAX_CUBE_MAP_TEXTURE_SIZE), - gl.gp(gl.MAX_FRAGMENT_UNIFORM_VECTORS), - gl.gp(gl.MAX_TEXTURE_IMAGE_UNITS), - gl.gp(gl.MAX_TEXTURE_SIZE), - gl.gp(gl.MAX_VARYING_VECTORS), - gl.gp(gl.MAX_VERTEX_ATTRIBS), - gl.gp(gl.MAX_VERTEX_TEXTURE_IMAGE_UNITS), - gl.gp(gl.MAX_VERTEX_UNIFORM_VECTORS), - gl.gp(gl.ALIASED_LINE_WIDTH_RANGE), - gl.gp(gl.ALIASED_POINT_SIZE_RANGE), - gl.gp(gl.MAX_VIEWPORT_DIMS), - gl.gs(gl.FRAGMENT_SHADER, gl.HIGH_INT), - gl.getSupportedExtensions(), - debugInfo ? gl.gp(debugInfo.UNMASKED_RENDERER_WEBGL) : gl.gp(gl.RENDERER), - drawBuffers ? gl.gp(drawBuffers.MAX_DRAW_BUFFERS_WEBGL) : 1, - anisotropy ? gl.gp(anisotropy.MAX_TEXTURE_MAX_ANISOTROPY_EXT) : 0, - ]; - } - - return MD5(JSON.stringify(hash)).toString(); -} - /** * Generate stable user id * * @returns {String} userId */ function generateUserId() { - var flavors = [ - // Blink and some browsers on iOS - 'chrome', - - // Safari on macOS - 'safari', - - // Chrome on iOS (checked in 85 on 13 and 87 on 14) - '__crWeb', - '__gCrWeb', - - // Yandex Browser on iOS, macOS and Android (checked in 21.2 on iOS 14, macOS and Android) - 'yandex', - - // Yandex Browser on iOS (checked in 21.2 on 14) - '__yb', - '__ybro', - - // Firefox on iOS (checked in 32 on 14) - '__firefox__', - - // Edge on iOS (checked in 46 on 14) - '__edgeTrackingPreventionStatistics', - 'webkit', - - // Opera Touch on iOS (checked in 2.6 on 14) - 'oprt', - - // Samsung Internet on Android (checked in 11.1) - 'samsungAr', - - // UC Browser on Android (checked in 12.10 and 13.0) - 'ucweb', - 'UCShellJava', - - // Puffin on Android (checked in 9.0) - 'puffinDevice', - ]; - - var flavor = null; - for (var i = 0; i < flavors.length; i++) { - if (window[flavors[i]] && typeof window[flavors[i]] === 'object') { - flavor = flavors[i]; - } - } - - var screen = [ - parseInt(window.screen.width), - parseInt(window.screen.height), - window.screen.availHeight, - window.screen.availWidth, - ]; - - var hash = [ - viewportHash(), - flavor, - navigator.webdriver, - navigator.language || - navigator.userLanguage || - navigator.browserLanguage || - navigator.systemLanguage || - null, - navigator.userAgent, - window.screen.colorDepth, - navigator.doNotTrack || navigator.msDoNotTrack || window.doNotTrack || null, - navigator.maxTouchPoints || navigator.msMaxTouchPoints || null, - navigator.vendor, - navigator.cpuClass, - navigator.oscpu, - navigator.deviceMemory, - navigator.hardwareConcurrency, - navigator.languages, - navigator.pdfViewerEnabled, - navigator.plugins, - window.chrome ? screen : null, - window.matchMedia('(color-gamut: rec2020)').matches, - window.matchMedia('(color-gamut: p3)').matches, - window.matchMedia('(color-gamut: srgb)').matches, - window.matchMedia('(prefers-contrast: no-preference)').matches, - window.matchMedia('(prefers-contrast: more)').matches, - window.matchMedia('(prefers-contrast: less)').matches, - window.matchMedia('(prefers-contrast: custom)').matches, - window.matchMedia('(inverted-colors: inverted)').matches, - window.matchMedia('(prefers-reduced-motion: reduce)').matches, - ]; - - hash = MD5(JSON.stringify(hash)).toString(); + var hash = MD5(navigator.userAgent).toString(); return hash; } @@ -373,7 +211,7 @@ export const spec = { }, onSetTargeting: function(bid) {}, onBidderError: function(error) { - console.log(error); + utils.logError(`${BIDDER_CODE} bidder error`, error); }, getUserSyncs: function(syncOptions, serverResponses, gdprConsent, uspConsent) {}, onTimeout: function(timeoutData) {}, From cf58233851f823a65bbd466623808a1ea3549a6b Mon Sep 17 00:00:00 2001 From: freedomadnetworkdev Date: Tue, 20 Aug 2024 15:11:35 -0400 Subject: [PATCH 06/15] Update fanAdapter.js --- modules/fanAdapter.js | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/modules/fanAdapter.js b/modules/fanAdapter.js index 0b8f3c517fa..7570822747d 100644 --- a/modules/fanAdapter.js +++ b/modules/fanAdapter.js @@ -65,7 +65,6 @@ function buildBidRequest(bid, bidderRequest) { at: 2, user: { coppa: config.getConfig('coppa') ? 1 : 0, - id: userId, } } @@ -150,6 +149,10 @@ export const spec = { const serverBody = serverResponse.body; let bidResponses = []; + if (!serverBody) { + return bidResponses; + } + serverBody.forEach((response) => { const bidResponse = { requestId: response.id, @@ -213,7 +216,10 @@ export const spec = { onBidderError: function(error) { utils.logError(`${BIDDER_CODE} bidder error`, error); }, - getUserSyncs: function(syncOptions, serverResponses, gdprConsent, uspConsent) {}, + getUserSyncs: function(syncOptions, serverResponses, gdprConsent, uspConsent) { + const syncs = []; + return syncs; + }, onTimeout: function(timeoutData) {}, supportedMediaTypes: [BANNER, NATIVE] } From e218167bc9f857510d0f04e1fb0dbb35b98ac4e4 Mon Sep 17 00:00:00 2001 From: freedomadnetworkdev Date: Tue, 20 Aug 2024 15:12:03 -0400 Subject: [PATCH 07/15] Update fanAdapter_spec.js --- test/spec/modules/fanAdapter_spec.js | 41 ++++++++-------------------- 1 file changed, 11 insertions(+), 30 deletions(-) diff --git a/test/spec/modules/fanAdapter_spec.js b/test/spec/modules/fanAdapter_spec.js index 97abe82c8ad..e74d3f33d11 100644 --- a/test/spec/modules/fanAdapter_spec.js +++ b/test/spec/modules/fanAdapter_spec.js @@ -2,7 +2,7 @@ import * as ajax from 'src/ajax.js'; import { expect } from 'chai'; import { spec } from 'modules/fanAdapter.js'; import { newBidder } from 'src/adapters/bidderFactory.js'; -import { BANNER, NATIVE, VIDEO } from 'src/mediaTypes.js'; +import { BANNER, NATIVE } from 'src/mediaTypes.js'; describe('Freedom Ad Network Bid Adapter', function () { describe('Test isBidRequestValid', function () { @@ -26,7 +26,14 @@ describe('Freedom Ad Network Bid Adapter', function () { it('valid bid should return true', function () { expect(spec.isBidRequestValid({ - params: { placementId: 'e6203f1e-bd6d-4f42-9895-d1a19cdb83c8' } + mediaTypes: { + [BANNER]: { + sizes: [[300, 250]] + } + }, + params: { + placementId: 'e6203f1e-bd6d-4f42-9895-d1a19cdb83c8' + } })).to.be.true; }); }); @@ -163,38 +170,12 @@ describe('Freedom Ad Network Bid Adapter', function () { expect(req.options).to.be.an('object'); expect(req.options.contentType).to.contain('application/json'); expect(req.options.customHeaders).to.be.an('object'); - expect(req.options.customHeaders['Authorization']).to.equal('Bearer 1d00c41fbf6bcf02b760c7f9e6266202'); expect(req.originalBidRequest).to.equal(bidRequest); - expect(req.data).to.equal('{"id":"' + bidRequest.bidId + '","tmax":3000,"placements":["' + bidRequest.params.placementId + '"],"test":0,"device":{"w":800,"h":600,"ua":"Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) HeadlessChrome/125.0.6422.141 Safari/537.36","language":"en","dnt":0},"at":2,"user":{"coppa":0,"id":"1d00c41fbf6bcf02b760c7f9e6266202","gdpr":1,"consent":"IwuyYwpjmnsauyYasIUWwe","usp":"Oush3@jmUw82has"}}'); + expect(req.data).to.equal('{"id":"' + bidRequest.bidId + '","tmax":3000,"placements":["' + bidRequest.params.placementId + '"],"test":0,"device":{"w":800,"h":600,"ua":"' + navigator.userAgent + '","language":"en","dnt":0},"at":2,"user":{"coppa":0,"gdpr":1,"consent":"IwuyYwpjmnsauyYasIUWwe","usp":"Oush3@jmUw82has"}}'); } }); - - it('random uid will be generate when userId is empty', function () { - const bidRequests = [{ - adUnitCode: 'test-div', - auctionId: 'b06c5141-fe8f-4cdf-9d7d-54415490a917', - bidId: '8064026a1776', - bidder: 'freedomadnetwork', - bidderRequestId: '15246a574e859f', - mediaTypes: { - banner: { sizes: [[300, 250]] } - }, - params: { - placementId: 'e6203f1e-bd6d-4f42-9895-d1a19cdb83c8' - } - }]; - - const reqs = spec.buildRequests(bidRequests, bidderRequest); - - let requestData; - expect(function () { - requestData = JSON.parse(reqs[0].data); - }).to.not.throw(); - - expect(requestData.user.id).to.not.be.empty; - }) }); describe('Test adapter request', function () { @@ -315,7 +296,7 @@ describe('Freedom Ad Network Bid Adapter', function () { it('onBidWon empty bid should not throw', function () { expect(spec.onBidWon({})).to.not.throw; - expect(ajaxStub.calledOnce).to.equal(false); + expect(ajaxStub.calledOnce).to.equal(true); }); it('onBidWon valid bid should not throw', function () { From 2f99acdd59bb63ef821fcce591801e456fc189ad Mon Sep 17 00:00:00 2001 From: freedomadnetworkdev Date: Tue, 20 Aug 2024 15:30:41 -0400 Subject: [PATCH 08/15] Update fanAdapter.js --- modules/fanAdapter.js | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/modules/fanAdapter.js b/modules/fanAdapter.js index 7570822747d..76c1a5b5194 100644 --- a/modules/fanAdapter.js +++ b/modules/fanAdapter.js @@ -4,6 +4,14 @@ import { ajax } from '../src/ajax.js'; import { BANNER, NATIVE } from '../src/mediaTypes.js'; import { config } from '../src/config.js'; import { registerBidder } from '../src/adapters/bidderFactory.js'; + +/** + * @typedef {import('../src/adapters/bidderFactory.js').BidderRequest} BidderRequest + * @typedef {import('../src/adapters/bidderFactory.js').BidRequest} BidRequest + * @typedef {import('../src/adapters/bidderFactory.js').Bid} Bid + * @typedef {import('../src/adapters/bidderFactory.js').ServerResponse} ServerResponse + */ + const BIDDER_CODE = 'freedomadnetwork'; const BASE_URL = 'https://srv.freedomadnetwork.com'; @@ -49,7 +57,7 @@ function getDevice() { /** * Build OpenRTB request from bidRequest and bidderRequest * - * @param {BidRequest} bidRequest + * @param {BidRequest} bid * @param {BidderRequest} bidderRequest * @returns {Request} */ From 24cf51889194c5ee324c5d2b4f664f30d331b7b3 Mon Sep 17 00:00:00 2001 From: freedomadnetworkdev Date: Tue, 20 Aug 2024 15:30:49 -0400 Subject: [PATCH 09/15] Update fanAdapter_spec.js From abe5b701de29c13ac580bf4f22aad948ad0d8d46 Mon Sep 17 00:00:00 2001 From: freedomadnetworkdev Date: Tue, 20 Aug 2024 15:51:21 -0400 Subject: [PATCH 10/15] Update fanAdapter.js --- modules/fanAdapter.js | 26 ++------------------------ 1 file changed, 2 insertions(+), 24 deletions(-) diff --git a/modules/fanAdapter.js b/modules/fanAdapter.js index 76c1a5b5194..24a4989eec8 100644 --- a/modules/fanAdapter.js +++ b/modules/fanAdapter.js @@ -36,24 +36,6 @@ function getLanguage() { return lang ? lang.split('-')[0] : 'en'; } -/** - * Get device info - * - * @returns {Object} - */ -function getDevice() { - const device = config.getConfig('device') || {}; - - device.w = device.w || window.screen.width; - device.h = device.h || window.screen.height; - device.ua = device.ua || navigator.userAgent; - device.language = device.language || getLanguage(); - device.dnt = typeof device.dnt === 'number' - ? device.dnt : (utils.getDNT() ? 1 : 0); - - return device; -} - /** * Build OpenRTB request from bidRequest and bidderRequest * @@ -68,12 +50,8 @@ function buildBidRequest(bid, bidderRequest) { id: bid.bidId, tmax: bidderRequest.timeout, placements: [bid.params.placementId], - test: config.getConfig('debug') ? 1 : 0, - device: getDevice(), - at: 2, - user: { - coppa: config.getConfig('coppa') ? 1 : 0, - } + at: 1, + user: {} } const gdprConsent = utils.deepAccess(bidderRequest, 'gdprConsent'); From 8a199942a5ed06da8d3e35237e95eab8b7dc36d4 Mon Sep 17 00:00:00 2001 From: freedomadnetworkdev Date: Tue, 20 Aug 2024 15:51:29 -0400 Subject: [PATCH 11/15] Update fanAdapter_spec.js --- test/spec/modules/fanAdapter_spec.js | 490 +++++++++++---------------- 1 file changed, 195 insertions(+), 295 deletions(-) diff --git a/test/spec/modules/fanAdapter_spec.js b/test/spec/modules/fanAdapter_spec.js index e74d3f33d11..24a4989eec8 100644 --- a/test/spec/modules/fanAdapter_spec.js +++ b/test/spec/modules/fanAdapter_spec.js @@ -1,313 +1,213 @@ -import * as ajax from 'src/ajax.js'; -import { expect } from 'chai'; -import { spec } from 'modules/fanAdapter.js'; -import { newBidder } from 'src/adapters/bidderFactory.js'; -import { BANNER, NATIVE } from 'src/mediaTypes.js'; - -describe('Freedom Ad Network Bid Adapter', function () { - describe('Test isBidRequestValid', function () { - it('undefined bid should return false', function () { - expect(spec.isBidRequestValid()).to.be.false; - }); - - it('null bid should return false', function () { - expect(spec.isBidRequestValid(null)).to.be.false; - }); - - it('bid.params should be set', function () { - expect(spec.isBidRequestValid({})).to.be.false; - }); - - it('bid.params.placementId should be set', function () { - expect(spec.isBidRequestValid({ - params: { foo: 'bar' } - })).to.be.false; - }); - - it('valid bid should return true', function () { - expect(spec.isBidRequestValid({ - mediaTypes: { - [BANNER]: { - sizes: [[300, 250]] - } - }, - params: { - placementId: 'e6203f1e-bd6d-4f42-9895-d1a19cdb83c8' - } - })).to.be.true; - }); - }); - - describe('Test buildRequests', function () { - const bidderRequest = { - auctionId: 'b06c5141-fe8f-4cdf-9d7d-54415490a917', - auctionStart: Date.now(), - bidderCode: 'myBidderCode', - bidderRequestId: '15246a574e859f', - refererInfo: { - page: 'http://example.com', - stack: ['http://example.com'] - }, - gdprConsent: { - gdprApplies: true, - consentString: 'IwuyYwpjmnsauyYasIUWwe' +import * as utils from '../src/utils.js'; +import MD5 from 'crypto-js/md5.js'; +import { ajax } from '../src/ajax.js'; +import { BANNER, NATIVE } from '../src/mediaTypes.js'; +import { config } from '../src/config.js'; +import { registerBidder } from '../src/adapters/bidderFactory.js'; + +/** + * @typedef {import('../src/adapters/bidderFactory.js').BidderRequest} BidderRequest + * @typedef {import('../src/adapters/bidderFactory.js').BidRequest} BidRequest + * @typedef {import('../src/adapters/bidderFactory.js').Bid} Bid + * @typedef {import('../src/adapters/bidderFactory.js').ServerResponse} ServerResponse + */ + +const BIDDER_CODE = 'freedomadnetwork'; +const BASE_URL = 'https://srv.freedomadnetwork.com'; + +/** + * Get user id from bid request. if no user id module used, return a new uuid. + * + * @param {BidRequest} bidRequest + * @returns {String} userId + */ +function getUserId(bidRequest) { + return generateUserId(); +} + +/** + * Get browser language + * + * @returns {String} language + */ +function getLanguage() { + const lang = (navigator.languages && navigator.languages[0]) || + navigator.language || navigator.userLanguage; + return lang ? lang.split('-')[0] : 'en'; +} + +/** + * Build OpenRTB request from bidRequest and bidderRequest + * + * @param {BidRequest} bid + * @param {BidderRequest} bidderRequest + * @returns {Request} + */ +function buildBidRequest(bid, bidderRequest) { + const userId = getUserId(bid); + + const payload = { + id: bid.bidId, + tmax: bidderRequest.timeout, + placements: [bid.params.placementId], + at: 1, + user: {} + } + + const gdprConsent = utils.deepAccess(bidderRequest, 'gdprConsent'); + if (!!gdprConsent && gdprConsent.gdprApplies) { + payload.user.gdpr = 1; + payload.user.consent = gdprConsent.consentString; + } + + const uspConsent = utils.deepAccess(bidderRequest, 'uspConsent'); + if (uspConsent) { + payload.user.usp = uspConsent; + } + + return { + method: 'POST', + url: BASE_URL + '/pb/req', + data: JSON.stringify(payload), + options: { + contentType: 'application/json', + withCredentials: false, + customHeaders: { + 'Accept-Language': 'en;q=10', + 'Authorization': 'Bearer ' + userId }, - uspConsent: 'Oush3@jmUw82has', - timeout: 3000 - }; - - it('build request object', function () { - const bidRequests = [ - { - adUnitCode: 'test-div', - auctionId: 'b06c5141-fe8f-4cdf-9d7d-54415490a917', - bidId: '8064026a1776', - bidder: 'freedomadnetwork', - bidderRequestId: '15246a574e859f', - mediaTypes: { - banner: { sizes: [[300, 250]] } - }, - params: { - placementId: 'e6203f1e-bd6d-4f42-9895-d1a19cdb83c8' - } - }, - { - adUnitCode: 'test-native', - auctionId: 'b06c5141-fe8f-4cdf-9d7d-54415490a917', - bidId: '8064026a1777', - bidder: 'freedomadnetwork', - bidderRequestId: '15246a574e859f', - mediaTypes: { - native: { - title: { - required: true, - len: 20, - }, - image: { - required: true, - sizes: [300, 250], - aspect_ratios: [{ - ratio_width: 1, - ratio_height: 1 - }] - }, - icon: { - required: true, - sizes: [60, 60], - aspect_ratios: [{ - ratio_width: 1, - ratio_height: 1 - }] - }, - sponsoredBy: { - required: true, - len: 20 - }, - body: { - required: true, - len: 140 - }, - cta: { - required: true, - len: 20, - } - } - }, - params: { - placementId: '3f50a79e-5582-4e5c-b1f4-9dcc1c82cece' - } - }, - { - adUnitCode: 'test-native2', - auctionId: 'b06c5141-fe8f-4cdf-9d7d-54415490a917', - bidId: '8064026a1778', - bidder: 'freedomadnetwork', - bidderRequestId: '15246a574e859f', - mediaTypes: { - native: { - title: {}, - image: {}, - icon: {}, - sponsoredBy: {}, - body: {}, - cta: {} - } - }, - params: { - placementId: '2015defc-19db-4cf6-926d-d2d0d32122fa', - } - }, - { - adUnitCode: 'test-native3', - auctionId: 'b06c5141-fe8f-4cdf-9d7d-54415490a917', - bidId: '8064026a1779', - bidder: 'freedomadnetwork', - bidderRequestId: '15246a574e859f', - mediaTypes: { - native: {}, - }, - params: { - placementId: '8064026a-9932-45ae-b804-03491302ad88' - } - } - ]; - - let reqs; - - expect(function () { - reqs = spec.buildRequests(bidRequests, bidderRequest); - }).to.not.throw(); - - expect(reqs).to.be.an('array').that.have.lengthOf(bidRequests.length); - - for (let i = 0, len = reqs.length; i < len; i++) { - const req = reqs[i]; - const bidRequest = bidRequests[i]; - - expect(req.method).to.equal('POST'); - expect(req.url).to.equal('https://srv.freedomadnetwork.com/pb/req'); + }, + originalBidRequest: bid + } +} + +/** + * Generate stable user id + * + * @returns {String} userId + */ +function generateUserId() { + var hash = MD5(navigator.userAgent).toString(); + + return hash; +} + +export const spec = { + code: BIDDER_CODE, + isBidRequestValid: function(bid) { + if (!bid) { + utils.logWarn(BIDDER_CODE, 'Invalid bid', bid); + + return false; + } - expect(req.options).to.be.an('object'); - expect(req.options.contentType).to.contain('application/json'); - expect(req.options.customHeaders).to.be.an('object'); + if (!bid.params) { + utils.logWarn(BIDDER_CODE, 'bid.params is required'); - expect(req.originalBidRequest).to.equal(bidRequest); + return false; + } - expect(req.data).to.equal('{"id":"' + bidRequest.bidId + '","tmax":3000,"placements":["' + bidRequest.params.placementId + '"],"test":0,"device":{"w":800,"h":600,"ua":"' + navigator.userAgent + '","language":"en","dnt":0},"at":2,"user":{"coppa":0,"gdpr":1,"consent":"IwuyYwpjmnsauyYasIUWwe","usp":"Oush3@jmUw82has"}}'); - } - }); - }); + if (!bid.params.placementId) { + utils.logWarn(BIDDER_CODE, 'bid.params.placementId is required'); - describe('Test adapter request', function () { - const adapter = newBidder(spec); + return false; + } - it('adapter.callBids exists and is a function', function () { - expect(adapter.callBids).to.be.a('function'); - }); - }); + var banner = utils.deepAccess(bid, 'mediaTypes.banner'); + if (banner === undefined) { + return false; + } - describe('Test response interpretResponse', function () { - it('Test main interpretResponse', function () { - const serverResponse = { - body: [{ - id: '8064026a1776', - bidid: '78e10bd4-aa67-40a6-b282-0f2697251eb3', - impid: '88faf7e7-bef8-43a5-9ef3-73db10c2af6b', - userId: '944c9c880be09af1e90da1f883538607', - cpm: 17.76, - currency: 'USD', - width: 300, - height: 250, - ttl: 60, - netRevenue: false, - crid: '03f3ed6f-1a9e-4276-8ad7-0dc5efae289e', - payload: '', - trackers: [], - mediaType: 'native', - domains: ['foo.com'], - }] - }; + return true; + }, + + buildRequests: function(validBidRequests, bidderRequest) { + return validBidRequests.map(bid => buildBidRequest(bid, bidderRequest)); + }, + + /** + * Unpack the response from the server into a list of bids. + * + * @param {ServerResponse} serverResponse A successful response from the server. + * @return {Bid[]} An array of bids which were nested inside the server. + */ + interpretResponse: function (serverResponse, bidRequest) { + const serverBody = serverResponse.body; + let bidResponses = []; + + if (!serverBody) { + return bidResponses; + } - const bidResponses = spec.interpretResponse(serverResponse, { - originalBidRequest: { - adUnitCode: 'test-div', - auctionId: 'b06c5141-fe8f-4cdf-9d7d-54415490a917', - bidId: '8064026a1776', - bidder: 'freedomadnetwork', - bidderRequestId: '15246a574e859f', - mediaTypes: { - banner: { sizes: [[300, 250]] } - }, - params: { - placementId: 'e6203f1e-bd6d-4f42-9895-d1a19cdb83c8' - } + serverBody.forEach((response) => { + const bidResponse = { + requestId: response.id, + bidid: response.bidid, + impid: response.impid, + userId: response.userId, + cpm: response.cpm, + currency: response.currency, + width: response.width, + height: response.height, + ad: response.payload, + ttl: response.ttl, + creativeId: response.crid, + netRevenue: response.netRevenue, + trackers: response.trackers, + meta: { + mediaType: response.mediaType, + advertiserDomains: response.domains, } - }); - - expect(bidResponses).to.be.an('array').that.is.not.empty; - - const bid = serverResponse.body[0]; - const bidResponse = bidResponses[0]; - - expect(bidResponse.requestId).to.equal(bid.id); - expect(bidResponse.bidid).to.equal(bid.bidid); - expect(bidResponse.impid).to.equal(bid.impid); - expect(bidResponse.userId).to.equal(bid.userId); - expect(bidResponse.cpm).to.equal(bid.cpm); - expect(bidResponse.currency).to.equal(bid.currency); - expect(bidResponse.width).to.equal(bid.width); - expect(bidResponse.height).to.equal(bid.height); - expect(bidResponse.ad).to.equal(bid.payload); - expect(bidResponse.ttl).to.equal(bid.ttl); - expect(bidResponse.creativeId).to.equal(bid.crid); - expect(bidResponse.netRevenue).to.equal(bid.netRevenue); - expect(bidResponse.trackers).to.equal(bid.trackers); - expect(bidResponse.meta.mediaType).to.equal(bid.mediaType); - expect(bidResponse.meta.advertiserDomains).to.equal(bid.domains); - }); - - it('Test empty server response', function () { - const bidResponses = spec.interpretResponse({}, {}); - - expect(bidResponses).to.be.an('array').that.is.empty; - }); - - it('Test empty bid response', function () { - const bidResponses = spec.interpretResponse({ body: [] }, {}); - - expect(bidResponses).to.be.an('array').that.is.empty; - }); - }); - - describe('Test getUserSyncs', function () { - it('getUserSyncs should return empty', function () { - const serverResponse = {}; - const syncOptions = {} - const userSyncPixels = spec.getUserSyncs(syncOptions, [serverResponse]) - expect(userSyncPixels).to.have.lengthOf(0); - }); - }); - - describe('Test onTimeout', function () { - it('onTimeout should not throw', function () { - expect(spec.onTimeout()).to.not.throw; - }); - }); - - describe('Test onBidWon', function () { - let sandbox, ajaxStub; + }; - beforeEach(function () { - sandbox = sinon.sandbox.create(); - ajaxStub = sandbox.stub(ajax, 'ajax'); + bidResponses.push(bidResponse); }); - afterEach(function () { - sandbox.restore(); - ajaxStub.restore(); - }); + return bidResponses; + }, - const bid = { - bidid: '78e10bd4-aa67-40a6-b282-0f2697251eb3', - impid: '88faf7e7-bef8-43a5-9ef3-73db10c2af6b', - cpm: 17.76, - trackers: ['foo.com'], + /** + * Register bidder specific code, which will execute if a bid from this bidder won the auction + * + * @param {Bid} bid The bid that won the auction + */ + onBidWon: function (bid) { + if (!bid) { + return; } - it('onBidWon empty bid should not throw', function () { - expect(spec.onBidWon({})).to.not.throw; - expect(ajaxStub.calledOnce).to.equal(true); - }); + const payload = { + id: bid.bidid, + impid: bid.impid, + t: bid.cpm, + } - it('onBidWon valid bid should not throw', function () { - expect(spec.onBidWon(bid)).to.not.throw; - expect(ajaxStub.calledOnce).to.equal(true); + ajax(BASE_URL + '/pb/imp', null, JSON.stringify(payload), { + method: 'POST', + customHeaders: { + 'Accept-Language': 'en;q=10', + 'Authorization': 'Bearer ' + bid.userId + }, }); - }); - describe('Test onSetTargeting', function () { - it('onSetTargeting should not throw', function () { - expect(spec.onSetTargeting()).to.not.throw; - }); - }); -}); + if (bid.trackers && bid.trackers.length > 0) { + for (var i = 0; i < bid.trackers.length; i++) { + if (bid.trackers[i].type == 0) { + utils.triggerPixel(bid.trackers[i].url); + } + } + } + }, + onSetTargeting: function(bid) {}, + onBidderError: function(error) { + utils.logError(`${BIDDER_CODE} bidder error`, error); + }, + getUserSyncs: function(syncOptions, serverResponses, gdprConsent, uspConsent) { + const syncs = []; + return syncs; + }, + onTimeout: function(timeoutData) {}, + supportedMediaTypes: [BANNER, NATIVE] +} + +registerBidder(spec); From c573b58405a45171d65dc90c44ba5be12bde2077 Mon Sep 17 00:00:00 2001 From: freedomadnetworkdev Date: Tue, 20 Aug 2024 15:54:25 -0400 Subject: [PATCH 12/15] Update fanAdapter.js --- modules/fanAdapter.js | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/modules/fanAdapter.js b/modules/fanAdapter.js index 24a4989eec8..8a32789c9b0 100644 --- a/modules/fanAdapter.js +++ b/modules/fanAdapter.js @@ -2,7 +2,6 @@ import * as utils from '../src/utils.js'; import MD5 from 'crypto-js/md5.js'; import { ajax } from '../src/ajax.js'; import { BANNER, NATIVE } from '../src/mediaTypes.js'; -import { config } from '../src/config.js'; import { registerBidder } from '../src/adapters/bidderFactory.js'; /** @@ -25,17 +24,6 @@ function getUserId(bidRequest) { return generateUserId(); } -/** - * Get browser language - * - * @returns {String} language - */ -function getLanguage() { - const lang = (navigator.languages && navigator.languages[0]) || - navigator.language || navigator.userLanguage; - return lang ? lang.split('-')[0] : 'en'; -} - /** * Build OpenRTB request from bidRequest and bidderRequest * From b91723932fd2558d786e74659f634fe80a7f4cb3 Mon Sep 17 00:00:00 2001 From: freedomadnetworkdev Date: Tue, 20 Aug 2024 16:04:56 -0400 Subject: [PATCH 13/15] Update fanAdapter_spec.js --- test/spec/modules/fanAdapter_spec.js | 492 ++++++++++++++++----------- 1 file changed, 297 insertions(+), 195 deletions(-) diff --git a/test/spec/modules/fanAdapter_spec.js b/test/spec/modules/fanAdapter_spec.js index 24a4989eec8..010ba91339d 100644 --- a/test/spec/modules/fanAdapter_spec.js +++ b/test/spec/modules/fanAdapter_spec.js @@ -1,213 +1,315 @@ -import * as utils from '../src/utils.js'; -import MD5 from 'crypto-js/md5.js'; -import { ajax } from '../src/ajax.js'; -import { BANNER, NATIVE } from '../src/mediaTypes.js'; -import { config } from '../src/config.js'; -import { registerBidder } from '../src/adapters/bidderFactory.js'; - -/** - * @typedef {import('../src/adapters/bidderFactory.js').BidderRequest} BidderRequest - * @typedef {import('../src/adapters/bidderFactory.js').BidRequest} BidRequest - * @typedef {import('../src/adapters/bidderFactory.js').Bid} Bid - * @typedef {import('../src/adapters/bidderFactory.js').ServerResponse} ServerResponse - */ - -const BIDDER_CODE = 'freedomadnetwork'; -const BASE_URL = 'https://srv.freedomadnetwork.com'; - -/** - * Get user id from bid request. if no user id module used, return a new uuid. - * - * @param {BidRequest} bidRequest - * @returns {String} userId - */ -function getUserId(bidRequest) { - return generateUserId(); -} - -/** - * Get browser language - * - * @returns {String} language - */ -function getLanguage() { - const lang = (navigator.languages && navigator.languages[0]) || - navigator.language || navigator.userLanguage; - return lang ? lang.split('-')[0] : 'en'; -} - -/** - * Build OpenRTB request from bidRequest and bidderRequest - * - * @param {BidRequest} bid - * @param {BidderRequest} bidderRequest - * @returns {Request} - */ -function buildBidRequest(bid, bidderRequest) { - const userId = getUserId(bid); - - const payload = { - id: bid.bidId, - tmax: bidderRequest.timeout, - placements: [bid.params.placementId], - at: 1, - user: {} - } - - const gdprConsent = utils.deepAccess(bidderRequest, 'gdprConsent'); - if (!!gdprConsent && gdprConsent.gdprApplies) { - payload.user.gdpr = 1; - payload.user.consent = gdprConsent.consentString; - } - - const uspConsent = utils.deepAccess(bidderRequest, 'uspConsent'); - if (uspConsent) { - payload.user.usp = uspConsent; - } - - return { - method: 'POST', - url: BASE_URL + '/pb/req', - data: JSON.stringify(payload), - options: { - contentType: 'application/json', - withCredentials: false, - customHeaders: { - 'Accept-Language': 'en;q=10', - 'Authorization': 'Bearer ' + userId - }, - }, - originalBidRequest: bid - } -} - -/** - * Generate stable user id - * - * @returns {String} userId - */ -function generateUserId() { - var hash = MD5(navigator.userAgent).toString(); - - return hash; -} - -export const spec = { - code: BIDDER_CODE, - isBidRequestValid: function(bid) { - if (!bid) { - utils.logWarn(BIDDER_CODE, 'Invalid bid', bid); - - return false; - } +import * as ajax from 'src/ajax.js'; +import { expect } from 'chai'; +import { spec } from 'modules/fanAdapter.js'; +import { newBidder } from 'src/adapters/bidderFactory.js'; +import { BANNER, NATIVE } from 'src/mediaTypes.js'; - if (!bid.params) { - utils.logWarn(BIDDER_CODE, 'bid.params is required'); +describe('Freedom Ad Network Bid Adapter', function () { + describe('Test isBidRequestValid', function () { + it('undefined bid should return false', function () { + expect(spec.isBidRequestValid()).to.be.false; + }); - return false; - } + it('null bid should return false', function () { + expect(spec.isBidRequestValid(null)).to.be.false; + }); - if (!bid.params.placementId) { - utils.logWarn(BIDDER_CODE, 'bid.params.placementId is required'); + it('bid.params should be set', function () { + expect(spec.isBidRequestValid({})).to.be.false; + }); - return false; - } + it('bid.params.placementId should be set', function () { + expect(spec.isBidRequestValid({ + params: { foo: 'bar' } + })).to.be.false; + }); - var banner = utils.deepAccess(bid, 'mediaTypes.banner'); - if (banner === undefined) { - return false; - } + it('valid bid should return true', function () { + expect(spec.isBidRequestValid({ + mediaTypes: { + [BANNER]: { + sizes: [[300, 250]] + } + }, + params: { + placementId: 'e6203f1e-bd6d-4f42-9895-d1a19cdb83c8' + } + })).to.be.true; + }); + }); - return true; - }, - - buildRequests: function(validBidRequests, bidderRequest) { - return validBidRequests.map(bid => buildBidRequest(bid, bidderRequest)); - }, - - /** - * Unpack the response from the server into a list of bids. - * - * @param {ServerResponse} serverResponse A successful response from the server. - * @return {Bid[]} An array of bids which were nested inside the server. - */ - interpretResponse: function (serverResponse, bidRequest) { - const serverBody = serverResponse.body; - let bidResponses = []; - - if (!serverBody) { - return bidResponses; - } + describe('Test buildRequests', function () { + const bidderRequest = { + auctionId: 'b06c5141-fe8f-4cdf-9d7d-54415490a917', + auctionStart: Date.now(), + bidderCode: 'myBidderCode', + bidderRequestId: '15246a574e859f', + refererInfo: { + page: 'http://example.com', + stack: ['http://example.com'] + }, + gdprConsent: { + gdprApplies: true, + consentString: 'IwuyYwpjmnsauyYasIUWwe' + }, + uspConsent: 'Oush3@jmUw82has', + timeout: 3000 + }; - serverBody.forEach((response) => { - const bidResponse = { - requestId: response.id, - bidid: response.bidid, - impid: response.impid, - userId: response.userId, - cpm: response.cpm, - currency: response.currency, - width: response.width, - height: response.height, - ad: response.payload, - ttl: response.ttl, - creativeId: response.crid, - netRevenue: response.netRevenue, - trackers: response.trackers, - meta: { - mediaType: response.mediaType, - advertiserDomains: response.domains, + it('build request object', function () { + const bidRequests = [ + { + adUnitCode: 'test-div', + auctionId: 'b06c5141-fe8f-4cdf-9d7d-54415490a917', + bidId: '8064026a1776', + bidder: 'freedomadnetwork', + bidderRequestId: '15246a574e859f', + mediaTypes: { + banner: { sizes: [[300, 250]] } + }, + params: { + placementId: 'e6203f1e-bd6d-4f42-9895-d1a19cdb83c8' + } + }, + { + adUnitCode: 'test-native', + auctionId: 'b06c5141-fe8f-4cdf-9d7d-54415490a917', + bidId: '8064026a1777', + bidder: 'freedomadnetwork', + bidderRequestId: '15246a574e859f', + mediaTypes: { + native: { + title: { + required: true, + len: 20, + }, + image: { + required: true, + sizes: [300, 250], + aspect_ratios: [{ + ratio_width: 1, + ratio_height: 1 + }] + }, + icon: { + required: true, + sizes: [60, 60], + aspect_ratios: [{ + ratio_width: 1, + ratio_height: 1 + }] + }, + sponsoredBy: { + required: true, + len: 20 + }, + body: { + required: true, + len: 140 + }, + cta: { + required: true, + len: 20, + } + } + }, + params: { + placementId: '3f50a79e-5582-4e5c-b1f4-9dcc1c82cece' + } + }, + { + adUnitCode: 'test-native2', + auctionId: 'b06c5141-fe8f-4cdf-9d7d-54415490a917', + bidId: '8064026a1778', + bidder: 'freedomadnetwork', + bidderRequestId: '15246a574e859f', + mediaTypes: { + native: { + title: {}, + image: {}, + icon: {}, + sponsoredBy: {}, + body: {}, + cta: {} + } + }, + params: { + placementId: '2015defc-19db-4cf6-926d-d2d0d32122fa', + } + }, + { + adUnitCode: 'test-native3', + auctionId: 'b06c5141-fe8f-4cdf-9d7d-54415490a917', + bidId: '8064026a1779', + bidder: 'freedomadnetwork', + bidderRequestId: '15246a574e859f', + mediaTypes: { + native: {}, + }, + params: { + placementId: '8064026a-9932-45ae-b804-03491302ad88' + } } + ]; + + let reqs; + + expect(function () { + reqs = spec.buildRequests(bidRequests, bidderRequest); + }).to.not.throw(); + + expect(reqs).to.be.an('array').that.have.lengthOf(bidRequests.length); + + for (let i = 0, len = reqs.length; i < len; i++) { + const req = reqs[i]; + const bidRequest = bidRequests[i]; + + expect(req.method).to.equal('POST'); + expect(req.url).to.equal('https://srv.freedomadnetwork.com/pb/req'); + + expect(req.options).to.be.an('object'); + expect(req.options.contentType).to.contain('application/json'); + expect(req.options.customHeaders).to.be.an('object'); + + expect(req.originalBidRequest).to.equal(bidRequest); + + var data = JSON.parse(req.data); + expect(data.id).to.equal(bidRequest.bidId); + expect(data.placements[0]).to.equal(bidRequest.params.placementId); + } + }); + }); + + describe('Test adapter request', function () { + const adapter = newBidder(spec); + + it('adapter.callBids exists and is a function', function () { + expect(adapter.callBids).to.be.a('function'); + }); + }); + + describe('Test response interpretResponse', function () { + it('Test main interpretResponse', function () { + const serverResponse = { + body: [{ + id: '8064026a1776', + bidid: '78e10bd4-aa67-40a6-b282-0f2697251eb3', + impid: '88faf7e7-bef8-43a5-9ef3-73db10c2af6b', + userId: '944c9c880be09af1e90da1f883538607', + cpm: 17.76, + currency: 'USD', + width: 300, + height: 250, + ttl: 60, + netRevenue: false, + crid: '03f3ed6f-1a9e-4276-8ad7-0dc5efae289e', + payload: '', + trackers: [], + mediaType: 'native', + domains: ['foo.com'], + }] }; - bidResponses.push(bidResponse); + const bidResponses = spec.interpretResponse(serverResponse, { + originalBidRequest: { + adUnitCode: 'test-div', + auctionId: 'b06c5141-fe8f-4cdf-9d7d-54415490a917', + bidId: '8064026a1776', + bidder: 'freedomadnetwork', + bidderRequestId: '15246a574e859f', + mediaTypes: { + banner: { sizes: [[300, 250]] } + }, + params: { + placementId: 'e6203f1e-bd6d-4f42-9895-d1a19cdb83c8' + } + } + }); + + expect(bidResponses).to.be.an('array').that.is.not.empty; + + const bid = serverResponse.body[0]; + const bidResponse = bidResponses[0]; + + expect(bidResponse.requestId).to.equal(bid.id); + expect(bidResponse.bidid).to.equal(bid.bidid); + expect(bidResponse.impid).to.equal(bid.impid); + expect(bidResponse.userId).to.equal(bid.userId); + expect(bidResponse.cpm).to.equal(bid.cpm); + expect(bidResponse.currency).to.equal(bid.currency); + expect(bidResponse.width).to.equal(bid.width); + expect(bidResponse.height).to.equal(bid.height); + expect(bidResponse.ad).to.equal(bid.payload); + expect(bidResponse.ttl).to.equal(bid.ttl); + expect(bidResponse.creativeId).to.equal(bid.crid); + expect(bidResponse.netRevenue).to.equal(bid.netRevenue); + expect(bidResponse.trackers).to.equal(bid.trackers); + expect(bidResponse.meta.mediaType).to.equal(bid.mediaType); + expect(bidResponse.meta.advertiserDomains).to.equal(bid.domains); }); - return bidResponses; - }, + it('Test empty server response', function () { + const bidResponses = spec.interpretResponse({}, {}); - /** - * Register bidder specific code, which will execute if a bid from this bidder won the auction - * - * @param {Bid} bid The bid that won the auction - */ - onBidWon: function (bid) { - if (!bid) { - return; - } + expect(bidResponses).to.be.an('array').that.is.empty; + }); - const payload = { - id: bid.bidid, - impid: bid.impid, - t: bid.cpm, - } + it('Test empty bid response', function () { + const bidResponses = spec.interpretResponse({ body: [] }, {}); - ajax(BASE_URL + '/pb/imp', null, JSON.stringify(payload), { - method: 'POST', - customHeaders: { - 'Accept-Language': 'en;q=10', - 'Authorization': 'Bearer ' + bid.userId - }, + expect(bidResponses).to.be.an('array').that.is.empty; }); + }); - if (bid.trackers && bid.trackers.length > 0) { - for (var i = 0; i < bid.trackers.length; i++) { - if (bid.trackers[i].type == 0) { - utils.triggerPixel(bid.trackers[i].url); - } - } + describe('Test getUserSyncs', function () { + it('getUserSyncs should return empty', function () { + const serverResponse = {}; + const syncOptions = {} + const userSyncPixels = spec.getUserSyncs(syncOptions, [serverResponse]) + expect(userSyncPixels).to.have.lengthOf(0); + }); + }); + + describe('Test onTimeout', function () { + it('onTimeout should not throw', function () { + expect(spec.onTimeout()).to.not.throw; + }); + }); + + describe('Test onBidWon', function () { + let sandbox, ajaxStub; + + beforeEach(function () { + sandbox = sinon.sandbox.create(); + ajaxStub = sandbox.stub(ajax, 'ajax'); + }); + + afterEach(function () { + sandbox.restore(); + ajaxStub.restore(); + }); + + const bid = { + bidid: '78e10bd4-aa67-40a6-b282-0f2697251eb3', + impid: '88faf7e7-bef8-43a5-9ef3-73db10c2af6b', + cpm: 17.76, + trackers: ['foo.com'], } - }, - onSetTargeting: function(bid) {}, - onBidderError: function(error) { - utils.logError(`${BIDDER_CODE} bidder error`, error); - }, - getUserSyncs: function(syncOptions, serverResponses, gdprConsent, uspConsent) { - const syncs = []; - return syncs; - }, - onTimeout: function(timeoutData) {}, - supportedMediaTypes: [BANNER, NATIVE] -} - -registerBidder(spec); + + it('onBidWon empty bid should not throw', function () { + expect(spec.onBidWon({})).to.not.throw; + expect(ajaxStub.calledOnce).to.equal(true); + }); + + it('onBidWon valid bid should not throw', function () { + expect(spec.onBidWon(bid)).to.not.throw; + expect(ajaxStub.calledOnce).to.equal(true); + }); + }); + + describe('Test onSetTargeting', function () { + it('onSetTargeting should not throw', function () { + expect(spec.onSetTargeting()).to.not.throw; + }); + }); +}); From e6b89a5aa0c9246f1935c355a7695d120da5775a Mon Sep 17 00:00:00 2001 From: freedomadnetworkdev Date: Wed, 21 Aug 2024 09:35:53 -0400 Subject: [PATCH 14/15] Update fanAdapter.js --- modules/fanAdapter.js | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/modules/fanAdapter.js b/modules/fanAdapter.js index 8a32789c9b0..2f24aca1c5f 100644 --- a/modules/fanAdapter.js +++ b/modules/fanAdapter.js @@ -53,6 +53,10 @@ function buildBidRequest(bid, bidderRequest) { payload.user.usp = uspConsent; } + if (userId) { + payload.user.id = userId; + } + return { method: 'POST', url: BASE_URL + '/pb/req', @@ -62,7 +66,6 @@ function buildBidRequest(bid, bidderRequest) { withCredentials: false, customHeaders: { 'Accept-Language': 'en;q=10', - 'Authorization': 'Bearer ' + userId }, }, originalBidRequest: bid @@ -168,13 +171,13 @@ export const spec = { id: bid.bidid, impid: bid.impid, t: bid.cpm, + u: bid.userId, } ajax(BASE_URL + '/pb/imp', null, JSON.stringify(payload), { method: 'POST', customHeaders: { 'Accept-Language': 'en;q=10', - 'Authorization': 'Bearer ' + bid.userId }, }); From 22ad8579def3a89ada09c1717007c4a43631773c Mon Sep 17 00:00:00 2001 From: freedomadnetworkdev Date: Wed, 21 Aug 2024 09:48:39 -0400 Subject: [PATCH 15/15] Update fanAdapter.js --- modules/fanAdapter.js | 28 ---------------------------- 1 file changed, 28 deletions(-) diff --git a/modules/fanAdapter.js b/modules/fanAdapter.js index 2f24aca1c5f..cdcc8d19889 100644 --- a/modules/fanAdapter.js +++ b/modules/fanAdapter.js @@ -1,5 +1,4 @@ import * as utils from '../src/utils.js'; -import MD5 from 'crypto-js/md5.js'; import { ajax } from '../src/ajax.js'; import { BANNER, NATIVE } from '../src/mediaTypes.js'; import { registerBidder } from '../src/adapters/bidderFactory.js'; @@ -14,16 +13,6 @@ import { registerBidder } from '../src/adapters/bidderFactory.js'; const BIDDER_CODE = 'freedomadnetwork'; const BASE_URL = 'https://srv.freedomadnetwork.com'; -/** - * Get user id from bid request. if no user id module used, return a new uuid. - * - * @param {BidRequest} bidRequest - * @returns {String} userId - */ -function getUserId(bidRequest) { - return generateUserId(); -} - /** * Build OpenRTB request from bidRequest and bidderRequest * @@ -32,8 +21,6 @@ function getUserId(bidRequest) { * @returns {Request} */ function buildBidRequest(bid, bidderRequest) { - const userId = getUserId(bid); - const payload = { id: bid.bidId, tmax: bidderRequest.timeout, @@ -53,10 +40,6 @@ function buildBidRequest(bid, bidderRequest) { payload.user.usp = uspConsent; } - if (userId) { - payload.user.id = userId; - } - return { method: 'POST', url: BASE_URL + '/pb/req', @@ -72,17 +55,6 @@ function buildBidRequest(bid, bidderRequest) { } } -/** - * Generate stable user id - * - * @returns {String} userId - */ -function generateUserId() { - var hash = MD5(navigator.userAgent).toString(); - - return hash; -} - export const spec = { code: BIDDER_CODE, isBidRequestValid: function(bid) {