mk9-prebid
Version:
Header Bidding Management Library
792 lines (701 loc) • 25.9 kB
JavaScript
import { expect } from 'chai';
import { spec, storage } from 'modules/winrBidAdapter.js';
import { newBidder } from 'src/adapters/bidderFactory.js';
import * as bidderFactory from 'src/adapters/bidderFactory.js';
import { auctionManager } from 'src/auctionManager.js';
import { deepClone } from 'src/utils.js';
import { config } from 'src/config.js';
const GATE_COOKIE_NAME = 'wnr_gate';
const ENDPOINT = 'https://ib.adnxs.com/ut/v3/prebid';
function getMediaTypeFromBid(bid) {
return bid.mediaTypes && Object.keys(bid.mediaTypes)[0];
}
describe('WinrAdapter', function () {
const adapter = newBidder(spec);
describe('inherited functions', function () {
it('exists and is a function', function () {
expect(adapter.callBids).to.exist.and.to.be.a('function');
});
});
describe('isBidRequestValid', function () {
let getCookieStub;
let cookiesAreEnabledStub;
beforeEach(function() {
getCookieStub = sinon.stub(storage, 'getCookie');
cookiesAreEnabledStub = sinon.stub(storage, 'cookiesAreEnabled');
});
afterEach(function() {
getCookieStub.restore();
cookiesAreEnabledStub.restore();
});
let placementId = '21543013';
let bid = {
'bidder': 'winr',
'params': {
'placementId': placementId,
'domParent': '.blog-post',
'child': 4
},
'adUnitCode': 'adunit-code',
'sizes': [[1, 1]],
'bidId': '2b21e2d141e6d4',
'bidderRequestId': '1dfdc89563b81a',
'auctionId': '0bc27fb0-ea39-4a5a-b1ba-5d83a5f28a69',
'mediaTypes': {
'banner': {}
},
};
describe('- with cookies disabled', function () {
beforeEach(function() {
cookiesAreEnabledStub.returns(false);
});
it('should return false', function () {
expect(storage.cookiesAreEnabled()).to.equal(false);
expect(spec.isBidRequestValid(bid)).to.equal(false);
});
});
describe('- with gate cookie set', function () {
beforeEach(function() {
getCookieStub.withArgs(GATE_COOKIE_NAME).returns('true');
});
it('should return false', function () {
expect(storage.getCookie(GATE_COOKIE_NAME)).to.not.equal(null);
expect(spec.isBidRequestValid(bid)).to.equal(false);
});
});
describe('- with cookies enabled and gate cookie not set', function () {
beforeEach(function() {
cookiesAreEnabledStub.returns(true);
getCookieStub.withArgs(GATE_COOKIE_NAME).returns(null);
});
it('should return true when required params found', function () {
expect(storage.cookiesAreEnabled()).to.equal(true);
expect(storage.getCookie(GATE_COOKIE_NAME)).to.equal(null);
expect(getMediaTypeFromBid(bid)).to.equal('banner');
expect(bid).to.have.deep.nested.property('params.placementId');
expect(bid.params.placementId).to.equal(placementId);
expect(spec.isBidRequestValid(bid)).to.equal(true);
});
});
it('should return false when mediaType is not banner', function () {
let bid = Object.assign({}, bid);
delete bid.mediaTypes;
bid.mediaTypes = {
'video': {}
};
expect(getMediaTypeFromBid(bid)).to.not.equal('banner');
expect(spec.isBidRequestValid(bid)).to.equal(false);
});
it('should return false when required params are not passed', function () {
let bid = Object.assign({}, bid);
delete bid.params;
bid.params = {
'placementId': 0
};
expect(spec.isBidRequestValid(bid)).to.equal(false);
});
});
describe('buildRequests', function () {
let getAdUnitsStub;
let bidRequests = [
{
'bidder': 'winr',
'params': {
'placementId': '21543013'
},
'adUnitCode': 'adunit-code',
'sizes': [[1, 1]],
'bidId': '2b21e2d141e6d4',
'bidderRequestId': '1dfdc89563b81a',
'auctionId': '0bc27fb0-ea39-4a5a-b1ba-5d83a5f28a69',
'transactionId': '270e4b6e-0acc-41c4-b253-b935f966fa7d'
}
];
beforeEach(function() {
getAdUnitsStub = sinon.stub(auctionManager, 'getAdUnits').callsFake(function() {
return [];
});
});
afterEach(function() {
getAdUnitsStub.restore();
});
it('should parse out private sizes', function () {
let bidRequest = Object.assign({},
bidRequests[0],
{
params: {
placementId: '21543013',
privateSizes: [1, 1]
}
}
);
const request = spec.buildRequests([bidRequest]);
const payload = JSON.parse(request.data);
expect(payload.tags[0].private_sizes).to.exist;
expect(payload.tags[0].private_sizes).to.deep.equal([{width: 1, height: 1}]);
});
it('should add publisher_id in request', function() {
let bidRequest = Object.assign({},
bidRequests[0],
{
params: {
placementId: '21543013',
publisherId: '1231234'
}
});
const request = spec.buildRequests([bidRequest]);
const payload = JSON.parse(request.data);
expect(payload.tags[0].publisher_id).to.exist;
expect(payload.tags[0].publisher_id).to.deep.equal(1231234);
expect(payload.publisher_id).to.exist;
expect(payload.publisher_id).to.deep.equal(1231234);
})
it('should add source and version to the tag', function () {
const request = spec.buildRequests(bidRequests);
const payload = JSON.parse(request.data);
expect(payload.sdk).to.exist;
expect(payload.sdk).to.deep.equal({
source: 'pbjs',
version: '$prebid.version$'
});
});
it('should not populate the ad_types array when adUnit.mediaTypes is undefined', function() {
const bidRequest = Object.assign({}, bidRequests[0]);
const request = spec.buildRequests([bidRequest]);
const payload = JSON.parse(request.data);
expect(payload.tags[0].ad_types).to.not.exist;
});
it('sends bid request to ENDPOINT via POST', function () {
const request = spec.buildRequests(bidRequests);
expect(request.url).to.equal(ENDPOINT);
expect(request.method).to.equal('POST');
});
it('should attach valid user params to the tag', function () {
let bidRequest = Object.assign({},
bidRequests[0],
{
params: {
placementId: '21543013',
user: {
externalUid: '123',
// dnt: false,
segments: [123, { id: 987, value: 876 }],
foobar: 'invalid'
}
}
}
);
const request = spec.buildRequests([bidRequest]);
const payload = JSON.parse(request.data);
expect(payload.user).to.exist;
expect(payload.user).to.deep.equal({
external_uid: '123',
// dnt: false
segments: [{id: 123}, {id: 987, value: 876}]
});
});
it('should attach reserve param when either bid param or getFloor function exists', function () {
let getFloorResponse = { currency: 'USD', floor: 3 };
let request, payload = null;
let bidRequest = deepClone(bidRequests[0]);
// 1 -> reserve not defined, getFloor not defined > empty
request = spec.buildRequests([bidRequest]);
payload = JSON.parse(request.data);
expect(payload.tags[0].reserve).to.not.exist;
// 2 -> reserve is defined, getFloor not defined > reserve is used
bidRequest.params = {
'placementId': '21543013',
'reserve': 0.5
};
request = spec.buildRequests([bidRequest]);
payload = JSON.parse(request.data);
expect(payload.tags[0].reserve).to.exist.and.to.equal(0.5);
// 3 -> reserve is defined, getFloor is defined > getFloor is used
bidRequest.getFloor = () => getFloorResponse;
request = spec.buildRequests([bidRequest]);
payload = JSON.parse(request.data);
expect(payload.tags[0].reserve).to.exist.and.to.equal(3);
});
it('should contain hb_source value for other media', function() {
let bidRequest = Object.assign({},
bidRequests[0],
{
mediaType: 'banner',
params: {
sizes: [[1, 1]],
placementId: 13144370
}
}
);
const request = spec.buildRequests([bidRequest]);
const payload = JSON.parse(request.data);
expect(payload.tags[0].hb_source).to.deep.equal(1);
});
it('should convert keyword params to proper form and attaches to request', function () {
let bidRequest = Object.assign({},
bidRequests[0],
{
params: {
placementId: '21543013',
keywords: {
single: 'val',
singleArr: ['val'],
singleArrNum: [5],
multiValMixed: ['value1', 2, 'value3'],
singleValNum: 123,
emptyStr: '',
emptyArr: [''],
badValue: {'foo': 'bar'} // should be dropped
}
}
}
);
const request = spec.buildRequests([bidRequest]);
const payload = JSON.parse(request.data);
expect(payload.tags[0].keywords).to.deep.equal([{
'key': 'single',
'value': ['val']
}, {
'key': 'singleArr',
'value': ['val']
}, {
'key': 'singleArrNum',
'value': ['5']
}, {
'key': 'multiValMixed',
'value': ['value1', '2', 'value3']
}, {
'key': 'singleValNum',
'value': ['123']
}, {
'key': 'emptyStr'
}, {
'key': 'emptyArr'
}]);
});
it('should add payment rules to the request', function () {
let bidRequest = Object.assign({},
bidRequests[0],
{
params: {
placementId: '21543013',
usePaymentRule: true
}
}
);
const request = spec.buildRequests([bidRequest]);
const payload = JSON.parse(request.data);
expect(payload.tags[0].use_pmt_rule).to.equal(true);
});
it('should add gpid to the request', function () {
let testGpid = '/12345/my-gpt-tag-0';
let bidRequest = deepClone(bidRequests[0]);
bidRequest.ortb2Imp = { ext: { data: { pbadslot: testGpid } } };
const request = spec.buildRequests([bidRequest]);
const payload = JSON.parse(request.data);
expect(payload.tags[0].gpid).to.exist.and.equal(testGpid)
});
it('should add gdpr consent information to the request', function () {
let consentString = 'BOJ8RZsOJ8RZsABAB8AAAAAZ+A==';
let bidderRequest = {
'bidderCode': 'winr',
'auctionId': '0bc27fb0-ea39-4a5a-b1ba-5d83a5f28a69',
'bidderRequestId': '1dfdc89563b81a',
'timeout': 3000,
'gdprConsent': {
consentString: consentString,
gdprApplies: true
}
};
bidderRequest.bids = bidRequests;
const request = spec.buildRequests(bidRequests, bidderRequest);
expect(request.options).to.deep.equal({withCredentials: true});
const payload = JSON.parse(request.data);
expect(payload.gdpr_consent).to.exist;
expect(payload.gdpr_consent.consent_string).to.exist.and.to.equal(consentString);
expect(payload.gdpr_consent.consent_required).to.exist.and.to.be.true;
});
it('should add us privacy string to payload', function() {
let consentString = '1YA-';
let bidderRequest = {
'bidderCode': 'winr',
'auctionId': '0bc27fb0-ea39-4a5a-b1ba-5d83a5f28a69',
'bidderRequestId': '1dfdc89563b81a',
'timeout': 3000,
'uspConsent': consentString
};
bidderRequest.bids = bidRequests;
const request = spec.buildRequests(bidRequests, bidderRequest);
const payload = JSON.parse(request.data);
expect(payload.us_privacy).to.exist;
expect(payload.us_privacy).to.exist.and.to.equal(consentString);
});
it('supports sending hybrid mobile app parameters', function () {
let appRequest = Object.assign({},
bidRequests[0],
{
params: {
placementId: '21543013',
app: {
id: 'B1O2W3M4AN.com.prebid.webview',
geo: {
lat: 40.0964439,
lng: -75.3009142
},
device_id: {
idfa: '4D12078D-3246-4DA4-AD5E-7610481E7AE', // Apple advertising identifier
aaid: '38400000-8cf0-11bd-b23e-10b96e40000d', // Android advertising identifier
md5udid: '5756ae9022b2ea1e47d84fead75220c8', // MD5 hash of the ANDROID_ID
sha1udid: '4DFAA92388699AC6539885AEF1719293879985BF', // SHA1 hash of the ANDROID_ID
windowsadid: '750c6be243f1c4b5c9912b95a5742fc5' // Windows advertising identifier
}
}
}
}
);
const request = spec.buildRequests([appRequest]);
const payload = JSON.parse(request.data);
expect(payload.app).to.exist;
expect(payload.app).to.deep.equal({
appid: 'B1O2W3M4AN.com.prebid.webview'
});
expect(payload.device.device_id).to.exist;
expect(payload.device.device_id).to.deep.equal({
aaid: '38400000-8cf0-11bd-b23e-10b96e40000d',
idfa: '4D12078D-3246-4DA4-AD5E-7610481E7AE',
md5udid: '5756ae9022b2ea1e47d84fead75220c8',
sha1udid: '4DFAA92388699AC6539885AEF1719293879985BF',
windowsadid: '750c6be243f1c4b5c9912b95a5742fc5'
});
expect(payload.device.geo).to.exist;
expect(payload.device.geo).to.deep.equal({
lat: 40.0964439,
lng: -75.3009142
});
});
it('should add referer info to payload', function () {
const bidRequest = Object.assign({}, bidRequests[0])
const bidderRequest = {
refererInfo: {
referer: 'https://example.com/page.html',
reachedTop: true,
numIframes: 2,
stack: [
'https://example.com/page.html',
'https://example.com/iframe1.html',
'https://example.com/iframe2.html'
]
}
}
const request = spec.buildRequests([bidRequest], bidderRequest);
const payload = JSON.parse(request.data);
expect(payload.referrer_detection).to.exist;
expect(payload.referrer_detection).to.deep.equal({
rd_ref: 'https%3A%2F%2Fexample.com%2Fpage.html',
rd_top: true,
rd_ifs: 2,
rd_stk: bidderRequest.refererInfo.stack.map((url) => encodeURIComponent(url)).join(',')
});
});
it('should populate member if available', function () {
const bidRequest = Object.assign({}, bidRequests[0], {
params: {
member: '11626'
}
});
const request = spec.buildRequests([bidRequest]);
const payload = JSON.parse(request.data);
expect(payload.member_id).to.deep.equal(11626);
});
it('should populate schain if available', function () {
const bidRequest = Object.assign({}, bidRequests[0], {
schain: {
ver: '1.0',
complete: 1,
nodes: [
{
'asi': 'blob.com',
'sid': '001',
'hp': 1
}
]
}
});
const request = spec.buildRequests([bidRequest]);
const payload = JSON.parse(request.data);
expect(payload.schain).to.deep.equal({
ver: '1.0',
complete: 1,
nodes: [
{
'asi': 'blob.com',
'sid': '001',
'hp': 1
}
]
});
});
it('should populate coppa if set in config', function () {
let bidRequest = Object.assign({}, bidRequests[0]);
sinon.stub(config, 'getConfig')
.withArgs('coppa')
.returns(true);
const request = spec.buildRequests([bidRequest]);
const payload = JSON.parse(request.data);
expect(payload.user.coppa).to.equal(true);
config.getConfig.restore();
});
it('should set the X-Is-Test customHeader if test flag is enabled', function () {
let bidRequest = Object.assign({}, bidRequests[0]);
sinon.stub(config, 'getConfig')
.withArgs('apn_test')
.returns(true);
const request = spec.buildRequests([bidRequest]);
expect(request.options.customHeaders).to.deep.equal({'X-Is-Test': 1});
config.getConfig.restore();
});
it('should always set withCredentials: true on the request.options', function () {
let bidRequest = Object.assign({}, bidRequests[0]);
const request = spec.buildRequests([bidRequest]);
expect(request.options.withCredentials).to.equal(true);
});
it('should set simple domain variant if purpose 1 consent is not given', function () {
let consentString = 'BOJ8RZsOJ8RZsABAB8AAAAAZ+A==';
let bidderRequest = {
'bidderCode': 'winr',
'auctionId': '1d1a030790a475',
'bidderRequestId': '22edbae2733bf6',
'timeout': 3000,
'gdprConsent': {
consentString: consentString,
gdprApplies: true,
apiVersion: 2,
vendorData: {
purpose: {
consents: {
1: false
}
}
}
}
};
bidderRequest.bids = bidRequests;
const request = spec.buildRequests(bidRequests, bidderRequest);
expect(request.url).to.equal('https://ib.adnxs-simple.com/ut/v3/prebid');
});
it('should populate eids when supported userIds are available', function () {
const bidRequest = Object.assign({}, bidRequests[0], {
userId: {
tdid: 'sample-userid',
uid2: { id: 'sample-uid2-value' },
criteoId: 'sample-criteo-userid',
netId: 'sample-netId-userid',
idl_env: 'sample-idl-userid',
flocId: {
id: 'sample-flocid-value',
version: 'chrome.1.0'
}
}
});
const request = spec.buildRequests([bidRequest]);
const payload = JSON.parse(request.data);
expect(payload.eids).to.deep.include({
source: 'adserver.org',
id: 'sample-userid',
rti_partner: 'TDID'
});
expect(payload.eids).to.deep.include({
source: 'criteo.com',
id: 'sample-criteo-userid',
});
expect(payload.eids).to.deep.include({
source: 'chrome.com',
id: 'sample-flocid-value'
});
expect(payload.eids).to.deep.include({
source: 'netid.de',
id: 'sample-netId-userid',
});
expect(payload.eids).to.deep.include({
source: 'liveramp.com',
id: 'sample-idl-userid'
});
expect(payload.eids).to.deep.include({
source: 'uidapi.com',
id: 'sample-uid2-value',
rti_partner: 'UID2'
});
});
});
describe('interpretResponse', function () {
let bfStub;
before(function() {
bfStub = sinon.stub(bidderFactory, 'getIabSubCategory');
});
after(function() {
bfStub.restore();
});
let response = {
'version': '3.0.0',
'tags': [
{
'uuid': '3db3773286ee59',
'tag_id': 10433394,
'auction_id': '4534722592064951574',
'nobid': false,
'no_ad_url': 'https://lax1-ib.adnxs.com/no-ad',
'timeout_ms': 10000,
'ad_profile_id': 27079,
'ads': [
{
'content_source': 'rtb',
'ad_type': 'banner',
'advertiserId': 4849978,
'buyer_member_id': 11626,
'brand_category_id': 0,
'creative_id': 29681110,
'media_type_id': 1,
'media_subtype_id': 1,
'cpm': 0.5,
'cpm_publisher_currency': 0.5,
'publisher_currency_code': '$',
'client_initiated_ad_counting': true,
'viewability': {
'config': '<script type=\'text/javascript\' async=\'true\' src=\'https://cdn.adnxs.com/v/s/152/trk.js#v;vk=appnexus.com-omid;tv=native1-18h;dom_id=%native_dom_id%;st=0;d=1x1;vc=iab;vid_ccr=1;tag_id=13232354;cb=https%3A%2F%2Fams1-ib.adnxs.com%2Fvevent%3Freferrer%3Dhttps253A%252F%252Ftestpages-pmahe.tp.adnxs.net%252F01_basic_single%26e%3DwqT_3QLNB6DNAwAAAwDWAAUBCLfl_-MFEMStk8u3lPTjRxih88aF0fq_2QsqNgkAAAECCCRAEQEHEAAAJEAZEQkAIREJACkRCQAxEQmoMOLRpwY47UhA7UhIAlCDy74uWJzxW2AAaM26dXjzjwWAAQGKAQNVU0SSAQEG8FCYAQGgAQGoAQGwAQC4AQHAAQTIAQLQAQDYAQDgAQDwAQCKAjt1ZignYScsIDI1Mjk4ODUsIDE1NTE4ODkwNzkpO3VmKCdyJywgOTc0OTQ0MDM2HgDwjZIC8QEha0RXaXBnajgtTHdLRUlQTHZpNFlBQ0NjOFZzd0FEZ0FRQVJJN1VoUTR0R25CbGdBWU1rR2FBQndMSGlrTDRBQlVvZ0JwQy1RQVFHWUFRR2dBUUdvQVFPd0FRQzVBZk90YXFRQUFDUkF3UUh6cldxa0FBQWtRTWtCbWo4dDA1ZU84VF9aQVFBQUEBAyRQQV80QUVBOVFFAQ4sQW1BSUFvQUlBdFFJBRAAdg0IeHdBSUF5QUlBNEFJQTZBSUEtQUlBZ0FNQm1BTUJxQVAFzIh1Z01KUVUxVE1UbzBNekl3NEFPVENBLi6aAmEhUXcxdGNRagUoEfQkblBGYklBUW9BRAl8AEEBqAREbzJEABRRSk1JU1EBGwRBQQGsAFURDAxBQUFXHQzwWNgCAOACrZhI6gIzaHR0cDovL3Rlc3RwYWdlcy1wbWFoZS50cC5hZG54cy5uZXQvMDFfYmFzaWNfc2luZ2xl8gITCg9DVVNUT01fTU9ERUxfSUQSAPICGgoWMhYAPExFQUZfTkFNRRIA8gIeCho2HQAIQVNUAT7wnElGSUVEEgCAAwCIAwGQAwCYAxegAwGqAwDAA-CoAcgDANgD8ao-4AMA6AMA-AMBgAQAkgQNL3V0L3YzL3ByZWJpZJgEAKIECjEwLjIuMTIuMzioBIqpB7IEDggAEAEYACAAKAAwADgCuAQAwAQAyAQA0gQOOTMyNSNBTVMxOjQzMjDaBAIIAeAEAfAEg8u-LogFAZgFAKAF______8BAxgBwAUAyQUABQEU8D_SBQkJBQt8AAAA2AUB4AUB8AWZ9CH6BQQIABAAkAYBmAYAuAYAwQYBITAAAPA_yAYA2gYWChAAOgEAGBAAGADgBgw.%26s%3D971dce9d49b6bee447c8a58774fb30b40fe98171;ts=1551889079;cet=0;cecb=\'></script>'
},
'rtb': {
'banner': {
'content': '<!-- Creative -->',
'width': 1,
'height': 1
},
'trackers': [
{
'impression_urls': [
'https://lax1-ib.adnxs.com/impression'
],
'video_events': {}
}
]
}
}
]
}
]
};
it('should get correct bid response', function () {
let expectedResponse = [
{
'adType': 'banner',
'requestId': '3db3773286ee59',
'auctionId': '28e94b67-b521-47b1-a284-e3cccc0a2707',
'cpm': 0.5,
'creativeId': 29681110,
'brandCategoryId': 0,
'dealId': undefined,
'currency': 'USD',
'netRevenue': true,
'ttl': 300,
'source': 'rtb',
'mediaSubtypeId': 1,
'mediaTypeId': 1,
'adUnitCode': 'code',
'buyerMemberId': 11626,
'appnexus': {
'buyerMemberId': 11626
},
'meta': {
'advertiserId': 4849978,
'placementId': 10433394,
'domParent': '.blog-post',
'child': 4
},
'width': 1,
'height': 1,
'banner': {
'content': '<!-- Creative -->',
'width': 1,
'height': 1,
'trackers': [
{
'impression_urls': [
'https://www.example.com'
]
}
]
},
'mediaType': 'banner',
'ad': '<!-- Wrapped Ad -->'
}
];
let bidderRequest = {
bids: [{
bidId: '3db3773286ee59',
adUnitCode: 'code',
params: {
'placementId': 10433394,
'domParent': '.blog-post',
'child': 4
}
}]
}
let result = spec.interpretResponse({ body: response }, {bidderRequest});
expect(Object.keys(result[0])).to.have.members(Object.keys(expectedResponse[0]));
});
it('handles nobid responses', function () {
let response = {
'version': '0.0.1',
'tags': [{
'uuid': '84ab500420319d',
'tag_id': 5976557,
'auction_id': '297492697822162468',
'nobid': true
}]
};
let bidderRequest;
let result = spec.interpretResponse({ body: response }, {bidderRequest});
expect(result.length).to.equal(0);
});
it('should add advertiser id', function() {
let responseAdvertiserId = deepClone(response);
responseAdvertiserId.tags[0].ads[0].advertiser_id = '123';
let bidderRequest = {
bids: [{
bidId: '3db3773286ee59',
adUnitCode: 'code'
}]
}
let result = spec.interpretResponse({ body: responseAdvertiserId }, {bidderRequest});
expect(Object.keys(result[0].meta)).to.include.members(['advertiserId']);
});
it('should add advertiserDomains', function() {
let responseAdvertiserId = deepClone(response);
responseAdvertiserId.tags[0].ads[0].adomain = ['123'];
let bidderRequest = {
bids: [{
bidId: '3db3773286ee59',
adUnitCode: 'code'
}]
}
let result = spec.interpretResponse({ body: responseAdvertiserId }, {bidderRequest});
expect(Object.keys(result[0].meta)).to.include.members(['advertiserDomains']);
expect(Object.keys(result[0].meta.advertiserDomains)).to.deep.equal([]);
});
it('should add params', function() {
let responseParams = deepClone(response);
let bidderRequest = {
bids: [{
bidId: '3db3773286ee59',
adUnitCode: 'code',
params: {
'placementId': 10433394,
'domParent': '.blog-post',
'child': 4
}
}]
}
let result = spec.interpretResponse({ body: responseParams }, {bidderRequest});
expect(Object.keys(result[0].meta)).to.include.members(['placementId', 'domParent', 'child']);
});
});
});