diff --git a/modules/insticatorBidAdapter.js b/modules/insticatorBidAdapter.js index 69fdd4a481a..5e3977237da 100644 --- a/modules/insticatorBidAdapter.js +++ b/modules/insticatorBidAdapter.js @@ -6,9 +6,9 @@ import { generateUUID, logError, } from '../src/utils.js'; -import { getStorageManager } from '../src/storageManager'; +import { getStorageManager } from '../src/storageManager.js'; -const storage = getStorageManager(); +export const storage = getStorageManager(); const BIDDER_CODE = 'insticator'; const ENDPOINT = 'https://ex.ingage.tech/v1/openrtb'; // production endpoint const USER_ID_KEY = 'hb_insticator_uid'; diff --git a/test/spec/modules/insticatorBidAdapter_spec.js b/test/spec/modules/insticatorBidAdapter_spec.js new file mode 100644 index 00000000000..1caee388f35 --- /dev/null +++ b/test/spec/modules/insticatorBidAdapter_spec.js @@ -0,0 +1,398 @@ +import { expect } from 'chai'; +import { spec, storage } from '../../../modules/InsticatorBidAdapter.js'; +import { newBidder } from 'src/adapters/bidderFactory.js' +import { userSync } from '../../../src/userSync.js'; + +const USER_ID_KEY = 'hb_insticator_uid'; +const USER_ID_DUMMY_VALUE = '74f78609-a92d-4cf1-869f-1b244bbfb5d2'; +const USER_ID_STUBBED = '12345678-1234-1234-1234-123456789abc'; + +let utils = require('src/utils.js'); + +describe('InsticatorBidAdapter', function () { + const adapter = newBidder(spec); + + let bidRequest = { + bidder: 'insticator', + adUnitCode: 'adunit-code', + params: { + adUnitId: '1a2b3c4d5e6f1a2b3c4d' + }, + sizes: [[300, 250], [300, 600]], + mediaTypes: { + banner: { + sizes: [[300, 250], [300, 600]] + } + }, + bidId: '30b31c1838de1e', + }; + + let bidderRequest = { + bidderRequestId: '22edbae2733bf6', + auctionId: '74f78609-a92d-4cf1-869f-1b244bbfb5d2', + timeout: 300, + gdprConsent: { + consentString: 'BOJ/P2HOJ/P2HABABMAAAAAZ+A==', + vendorData: {}, + gdprApplies: true + }, + refererInfo: { + numIframes: 0, + reachedTop: true, + referer: 'https://example.com', + stack: ['https://example.com'] + }, + }; + + describe('.code', function () { + it('should return a bidder code of insticator', function () { + expect(spec.code).to.equal('insticator') + }) + }) + + describe('inherited functions', function () { + it('should exist and be a function', function () { + expect(adapter.callBids).to.exist.and.to.be.a('function') + }) + }) + + describe('isBidRequestValid', function () { + it('should return true if the bid is valid', function () { + expect(spec.isBidRequestValid(bidRequest)).to.be.true; + }); + + it('should return false if there is no adUnitId param', () => { + expect(spec.isBidRequestValid({...bidRequest, ...{params: {}}})).to.be.false; + }); + + it('should return false if there is no mediaTypes', () => { + expect(spec.isBidRequestValid({...bidRequest, ...{mediaTypes: {}}})).to.be.false; + }); + + it('should return false if there are no banner sizes and no sizes', () => { + bidRequest.mediaTypes.banner = {}; + expect(spec.isBidRequestValid({...bidRequest, ...{sizes: {}}})).to.be.false; + }); + + it('should return true if there is sizes and no banner sizes', () => { + expect(spec.isBidRequestValid(bidRequest)).to.be.true; + }); + + it('should return true if there is banner sizes and no sizes', () => { + bidRequest.mediaTypes.banner.sizes = [[300, 250], [300, 600]]; + expect(spec.isBidRequestValid({...bidRequest, ...{sizes: {}}})).to.be.true; + }); + }); + + describe('buildRequests', function () { + let getDataFromLocalStorageStub, localStorageIsEnabledStub; + let getCookieStub, cookiesAreEnabledStub; + let sandbox; + + beforeEach(() => { + getDataFromLocalStorageStub = sinon.stub(storage, 'getDataFromLocalStorage'); + localStorageIsEnabledStub = sinon.stub(storage, 'localStorageIsEnabled'); + getCookieStub = sinon.stub(storage, 'getCookie'); + cookiesAreEnabledStub = sinon.stub(storage, 'cookiesAreEnabled'); + + sandbox = sinon.sandbox.create(); + sandbox.stub(utils, 'generateUUID').returns(USER_ID_STUBBED); + }); + + afterEach(() => { + sandbox.restore(); + getDataFromLocalStorageStub.restore(); + localStorageIsEnabledStub.restore(); + getCookieStub.restore(); + cookiesAreEnabledStub.restore(); + }); + + const serverRequests = spec.buildRequests([bidRequest], bidderRequest); + it('should create a request', function () { + expect(serverRequests).to.have.length(1); + }); + + const serverRequest = serverRequests[0]; + it('should create a request object with method, URL, options and data', function () { + expect(serverRequest).to.exist; + expect(serverRequest.method).to.exist; + expect(serverRequest.url).to.exist; + expect(serverRequest.options).to.exist; + expect(serverRequest.data).to.exist; + }); + + it('should return POST method', function () { + expect(serverRequest.method).to.equal('POST'); + }); + + it('should return valid URL', function () { + expect(serverRequest.url).to.equal('https://ex.ingage.tech/v1/openrtb'); + }); + + it('should return valid options', function () { + expect(serverRequest.options).to.be.an('object'); + expect(serverRequest.options.contentType).to.equal('application/json'); + expect(serverRequest.options.withCredentials).to.be.true; + }); + + it('should return valid data if array of bids is valid', function () { + localStorageIsEnabledStub.returns(true); + cookiesAreEnabledStub.returns(false); + localStorage.setItem(USER_ID_KEY, USER_ID_DUMMY_VALUE); + + const requests = spec.buildRequests([bidRequest], bidderRequest); + const data = JSON.parse(requests[0].data); + + expect(data).to.be.an('object'); + expect(data).to.have.all.keys('id', 'tmax', 'source', 'site', 'device', 'regs', 'user', 'imp'); + expect(data.id).to.equal(bidderRequest.bidderRequestId); + expect(data.tmax).to.equal(bidderRequest.timeout); + expect(data.source).to.eql({ + fd: 1, + tid: bidderRequest.auctionId, + }); + expect(data.site).to.be.an('object'); + expect(data.site.domain).not.to.be.empty; + expect(data.site.page).not.to.be.empty; + expect(data.site.ref).to.equal(bidderRequest.refererInfo.referer); + expect(data.device).to.be.an('object'); + expect(data.device.w).to.equal(window.innerWidth); + expect(data.device.h).to.equal(window.innerHeight); + expect(data.device.js).to.equal(true); + expect(data.device.ext).to.be.an('object'); + expect(data.device.ext.localStorage).to.equal(true); + expect(data.device.ext.cookies).to.equal(false); + expect(data.regs).to.be.an('object'); + expect(data.regs.ext.gdpr).to.equal(1); + expect(data.regs.ext.gdprConsentString).to.equal(bidderRequest.gdprConsent.consentString); + expect(data.user).to.be.an('object'); + expect(data.user.id).to.equal(USER_ID_DUMMY_VALUE); + expect(data.imp).to.be.an('array').that.have.lengthOf(1); + expect(data.imp).to.deep.equal([{ + id: bidRequest.bidId, + tagid: bidRequest.adUnitCode, + banner: { + format: [ + {w: 300, h: 250}, + {w: 300, h: 600}, + ] + }, + ext: { + insticator: { + adUnitId: bidRequest.params.adUnitId, + }, + } + }]); + }); + + it('should generate new userId if not valid user is stored', function () { + localStorageIsEnabledStub.returns(true); + localStorage.setItem(USER_ID_KEY, 'fake-user-id'); + + const requests = spec.buildRequests([bidRequest], bidderRequest); + const data = JSON.parse(requests[0].data); + + expect(data.user.id).to.equal(USER_ID_STUBBED); + }); + it('should return empty regs object if no gdprConsent is passed', function () { + const requests = spec.buildRequests([bidRequest], {...bidderRequest, ...{gdprConsent: false}}); + const data = JSON.parse(requests[0].data); + expect(data.regs).to.be.an('object').that.is.empty; + }); + it('should return empty array if no valid requests are passed', function () { + expect(spec.buildRequests([], bidderRequest)).to.be.an('array').that.have.lengthOf(0); + }); + }); + + describe('interpretResponse', function () { + const bidRequests = { + method: 'POST', + url: 'https://ex.ingage.tech/v1/openrtb', + options: { + contentType: 'application/json', + withCredentials: true, + }, + data: '', + bidderRequest: { + bidderRequestId: '22edbae2733bf6', + auctionId: '74f78609-a92d-4cf1-869f-1b244bbfb5d2', + timeout: 300, + bids: [ + { + bidder: 'insticator', + params: { + adUnitId: '1a2b3c4d5e6f1a2b3c4d' + }, + adUnitCode: 'adunit-code-1', + sizes: [[300, 250], [300, 600]], + mediaTypes: { + banner: { + sizes: [[300, 250], [300, 600]] + } + }, + bidId: 'bid1', + }, + { + bidder: 'insticator', + params: { + adUnitId: '1a2b3c4d5e6f1a2b3c4d' + }, + adUnitCode: 'adunit-code-2', + sizes: [[120, 600], [300, 600], [160, 600]], + mediaTypes: { + banner: { + sizes: [[300, 250], [300, 600]] + } + }, + bidId: 'bid2', + }, + { + bidder: 'insticator', + params: { + adUnitId: '1a2b3c4d5e6f1a2b3c4d' + }, + adUnitCode: 'adunit-code-3', + sizes: [[120, 600], [300, 600], [160, 600]], + mediaTypes: { + banner: { + sizes: [[300, 250], [300, 600]] + } + }, + bidId: 'bid3', + } + ] + } + }; + + const bidResponse = { + body: { + id: '22edbae2733bf6', + bidid: 'foo9876', + cur: 'USD', + seatbid: [ + { + seat: 'some-dsp', + bid: [ + { + impid: 'bid1', + crid: 'crid1', + price: 0.5, + w: 300, + h: 200, + adm: 'adm1', + exp: 60, + }, + { + impid: 'bid2', + crid: 'crid2', + price: 1.5, + w: 600, + h: 200, + adm: 'adm2' + }, + { + impid: 'bid3', + crid: 'crid3', + price: 5.0, + w: 300, + h: 200, + adm: 'adm3' + } + ], + }, + ] + } + }; + + const prebidResponse = [ + { + requestId: 'bid1', + creativeId: 'crid1', + cpm: 0.5, + currency: 'USD', + netRevenue: true, + ttl: 60, + width: 300, + height: 200, + mediaType: 'banner', + ad: 'adm1', + adUnitCode: 'adunit-code-1', + }, + { + requestId: 'bid2', + creativeId: 'crid2', + cpm: 1.5, + currency: 'USD', + netRevenue: true, + ttl: 300, + width: 600, + height: 200, + mediaType: 'banner', + ad: 'adm2', + adUnitCode: 'adunit-code-2', + }, + { + requestId: 'bid3', + creativeId: 'crid3', + cpm: 5.0, + currency: 'USD', + netRevenue: true, + ttl: 300, + width: 300, + height: 200, + mediaType: 'banner', + ad: 'adm3', + adUnitCode: 'adunit-code-3', + }, + ]; + + it('should map bidResponse to prebidResponse', function () { + const response = spec.interpretResponse(bidResponse, bidRequests); + response.forEach((resp, i) => { + expect(resp).to.deep.equal(prebidResponse[i]); + }); + }); + + it('should return empty response if bidderRequestId is invalid', function () { + const response = Object.assign({}, bidResponse); + response.body.id = 'fake-id'; + expect(spec.interpretResponse(response, bidRequests)).to.have.length(0); + }); + + it('should return empty response if there is no seatbid array in response', function () { + const response = Object.assign({}, bidResponse); + delete response.body.seatbid; + expect(spec.interpretResponse(response, bidRequests)).to.have.length(0); + }); + }); + + describe('getUserSyncs', function () { + const bidResponse = [{ + body: { + ext: { + sync: [{ + code: 'so', + delay: 0 + }] + } + } + }]; + + it('should return one user sync', function () { + expect(spec.getUserSyncs({}, bidResponse)).to.deep.equal([{ + code: 'so', + delay: 0 + }]); + }) + + it('should return an empty array when sync is enabled but there are no bidResponses', function () { + expect(spec.getUserSyncs({}, [])).to.have.length(0); + }) + + it('should return an empty array when sync is enabled but no sync ext returned', function () { + const response = Object.assign({}, bidResponse[0]); + delete response.body.ext.sync; + expect(spec.getUserSyncs({}, [response])).to.have.length(0); + }) + }); +});