prebid.js 8.1.0 → 8.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.devcontainer/devcontainer.json +3 -1
- package/dist/33acrossBidAdapter.js +1 -1
- package/dist/33acrossIdSystem.js +1 -1
- package/dist/adagioBidAdapter.js +1 -1
- package/dist/adbookpspBidAdapter.js +1 -1
- package/dist/adgenerationBidAdapter.js +1 -1
- package/dist/admanBidAdapter.js +1 -1
- package/dist/adqueryBidAdapter.js +1 -1
- package/dist/adrelevantisBidAdapter.js +1 -1
- package/dist/adtrgtmeBidAdapter.js +1 -1
- package/dist/adxcgBidAdapter.js +1 -1
- package/dist/adyoulikeBidAdapter.js +1 -1
- package/dist/ajaBidAdapter.js +1 -1
- package/dist/amxBidAdapter.js +1 -1
- package/dist/amxIdSystem.js +1 -1
- package/dist/appierAnalyticsAdapter.js +1 -1
- package/dist/appnexusBidAdapter.js +1 -1
- package/dist/asoBidAdapter.js +1 -1
- package/dist/axonixBidAdapter.js +1 -1
- package/dist/bidglassBidAdapter.js +1 -1
- package/dist/big-richmediaBidAdapter.js +1 -1
- package/dist/bridBidAdapter.js +1 -0
- package/dist/bridgewellBidAdapter.js +1 -1
- package/dist/brightMountainMediaBidAdapter.js +1 -1
- package/dist/carodaBidAdapter.js +1 -1
- package/dist/categoryTranslation.js +1 -1
- package/dist/chtnwBidAdapter.js +1 -1
- package/dist/cmp.js +1 -0
- package/dist/concertBidAdapter.js +1 -1
- package/dist/connectadBidAdapter.js +1 -1
- package/dist/consentManagement.js +1 -1
- package/dist/consentManagementGpp.js +1 -1
- package/dist/consentManagementUsp.js +1 -1
- package/dist/consumableBidAdapter.js +1 -1
- package/dist/conversantAnalyticsAdapter.js +1 -1
- package/dist/conversantBidAdapter.js +1 -1
- package/dist/craftBidAdapter.js +1 -1
- package/dist/criteoBidAdapter.js +1 -1
- package/dist/cwireBidAdapter.js +1 -1
- package/dist/dependencies.json +12 -0
- package/dist/dspxBidAdapter.js +1 -1
- package/dist/eplanningBidAdapter.js +1 -1
- package/dist/euidIdSystem.js +1 -1
- package/dist/feedadBidAdapter.js +1 -1
- package/dist/finativeBidAdapter.js +1 -1
- package/dist/freewheel-sspBidAdapter.js +1 -1
- package/dist/gmosspBidAdapter.js +1 -1
- package/dist/goldbachBidAdapter.js +1 -1
- package/dist/gppControl_usnat.js +1 -0
- package/dist/greenbidsAnalyticsAdapter.js +1 -1
- package/dist/greenbidsRtdProvider.js +1 -1
- package/dist/gridBidAdapter.js +1 -1
- package/dist/gumgumBidAdapter.js +1 -1
- package/dist/h12mediaBidAdapter.js +1 -1
- package/dist/hypelabBidAdapter.js +1 -1
- package/dist/id5IdSystem.js +1 -1
- package/dist/imdsBidAdapter.js +1 -1
- package/dist/improvedigitalBidAdapter.js +1 -1
- package/dist/insticatorBidAdapter.js +1 -1
- package/dist/intentIqIdSystem.js +1 -1
- package/dist/ixBidAdapter.js +1 -1
- package/dist/justpremiumBidAdapter.js +1 -1
- package/dist/kargoBidAdapter.js +1 -1
- package/dist/konduitAnalyticsAdapter.js +1 -1
- package/dist/kueezBidAdapter.js +1 -1
- package/dist/kueezRtbBidAdapter.js +1 -1
- package/dist/kulturemediaBidAdapter.js +1 -1
- package/dist/lassoBidAdapter.js +1 -1
- package/dist/lifestreetBidAdapter.js +1 -1
- package/dist/liveIntentIdSystem.js +1 -1
- package/dist/logicadBidAdapter.js +1 -1
- package/dist/loglyliftBidAdapter.js +1 -1
- package/dist/magniteAnalyticsAdapter.js +1 -1
- package/dist/malltvAnalyticsAdapter.js +1 -1
- package/dist/marsmediaBidAdapter.js +1 -1
- package/dist/mediafuseBidAdapter.js +1 -1
- package/dist/mediasquareBidAdapter.js +1 -1
- package/dist/mgidBidAdapter.js +1 -1
- package/dist/minutemediaBidAdapter.js +1 -1
- package/dist/minutemediaplusBidAdapter.js +1 -1
- package/dist/mspa.js +1 -0
- package/dist/nexx360BidAdapter.js +1 -1
- package/dist/not-for-prod/prebid.js +136 -132
- package/dist/oguryBidAdapter.js +1 -1
- package/dist/onetagBidAdapter.js +1 -1
- package/dist/ooloAnalyticsAdapter.js +1 -1
- package/dist/optidigitalBidAdapter.js +1 -1
- package/dist/outbrainBidAdapter.js +1 -1
- package/dist/oxxionRtdProvider.js +1 -1
- package/dist/parrableIdSystem.js +1 -1
- package/dist/pixfutureBidAdapter.js +1 -1
- package/dist/prebid-core.js +1 -1
- package/dist/publinkIdSystem.js +1 -1
- package/dist/pubmaticBidAdapter.js +1 -1
- package/dist/pubwiseAnalyticsAdapter.js +1 -1
- package/dist/pxyzBidAdapter.js +1 -1
- package/dist/quantcastBidAdapter.js +1 -1
- package/dist/readpeakBidAdapter.js +1 -1
- package/dist/relaidoBidAdapter.js +1 -1
- package/dist/retailspotBidAdapter.js +1 -1
- package/dist/rhythmoneBidAdapter.js +1 -1
- package/dist/riseBidAdapter.js +1 -1
- package/dist/rubiconBidAdapter.js +1 -1
- package/dist/seedingAllianceBidAdapter.js +1 -1
- package/dist/seedtagBidAdapter.js +1 -1
- package/dist/sharethroughAnalyticsAdapter.js +1 -1
- package/dist/sharethroughBidAdapter.js +1 -1
- package/dist/shinezBidAdapter.js +1 -1
- package/dist/smaatoBidAdapter.js +1 -1
- package/dist/smartadserverBidAdapter.js +1 -1
- package/dist/smartxBidAdapter.js +1 -1
- package/dist/smilewantedBidAdapter.js +1 -1
- package/dist/sonobiBidAdapter.js +1 -1
- package/dist/sovrnAnalyticsAdapter.js +1 -1
- package/dist/sovrnBidAdapter.js +1 -1
- package/dist/sspBCBidAdapter.js +1 -1
- package/dist/stvBidAdapter.js +1 -1
- package/dist/sublimeBidAdapter.js +1 -1
- package/dist/targetVideoBidAdapter.js +1 -1
- package/dist/teadsBidAdapter.js +1 -1
- package/dist/trionBidAdapter.js +1 -1
- package/dist/tripleliftBidAdapter.js +1 -1
- package/dist/ttdBidAdapter.js +1 -1
- package/dist/ucfunnelAnalyticsAdapter.js +1 -1
- package/dist/uid2IdSystem.js +1 -1
- package/dist/underdogmediaBidAdapter.js +1 -1
- package/dist/undertoneBidAdapter.js +1 -1
- package/dist/userId.js +1 -1
- package/dist/vidazooBidAdapter.js +1 -1
- package/dist/videobyteBidAdapter.js +1 -1
- package/dist/visxBidAdapter.js +1 -1
- package/dist/vuukleBidAdapter.js +1 -1
- package/dist/widespaceBidAdapter.js +1 -1
- package/dist/winrBidAdapter.js +1 -1
- package/dist/yahoosspBidAdapter.js +1 -1
- package/dist/yieldmoBidAdapter.js +1 -1
- package/dist/yieldoneAnalyticsAdapter.js +1 -1
- package/libraries/cmp/cmpClient.js +139 -0
- package/libraries/mspa/activityControls.js +91 -0
- package/modules/admanBidAdapter.js +5 -0
- package/modules/bridBidAdapter.js +223 -0
- package/modules/categoryTranslation.js +3 -2
- package/modules/consentManagement.js +12 -86
- package/modules/consentManagementGpp.js +47 -126
- package/modules/consentManagementUsp.js +19 -97
- package/modules/gppControl_usnat.js +11 -0
- package/modules/intentIqIdSystem.js +6 -5
- package/modules/liveIntentIdSystem.js +8 -3
- package/modules/mediasquareBidAdapter.js +19 -23
- package/modules/oxxionRtdProvider.js +124 -11
- package/modules/oxxionRtdProvider.md +19 -4
- package/modules/tripleliftBidAdapter.js +21 -1
- package/modules/userId/eids.js +29 -0
- package/modules/userId/eids.md +19 -2
- package/modules/userId/index.js +78 -29
- package/modules/userId/userId.md +3 -0
- package/package.json +1 -1
- package/src/activities/params.js +4 -1
- package/test/spec/libraries/cmp/cmpClient_spec.js +233 -0
- package/test/spec/libraries/mspa/activityControls_spec.js +315 -0
- package/test/spec/modules/admanBidAdapter_spec.js +8 -2
- package/test/spec/modules/adqueryBidAdapter_spec.js +5 -1
- package/test/spec/modules/bridBidAdapter_spec.js +129 -0
- package/test/spec/modules/byDataAnalyticsAdapter_spec.js +9 -7
- package/test/spec/modules/chtnwBidAdapter_spec.js +4 -1
- package/test/spec/modules/consentManagementGpp_spec.js +84 -7
- package/test/spec/modules/consentManagement_spec.js +8 -18
- package/test/spec/modules/datablocksBidAdapter_spec.js +7 -3
- package/test/spec/modules/eids_spec.js +87 -0
- package/test/spec/modules/insticatorBidAdapter_spec.js +6 -2
- package/test/spec/modules/intentIqIdSystem_spec.js +36 -2
- package/test/spec/modules/ixBidAdapter_spec.js +40 -12
- package/test/spec/modules/lassoBidAdapter_spec.js +6 -4
- package/test/spec/modules/liveIntentIdMinimalSystem_spec.js +17 -2
- package/test/spec/modules/liveIntentIdSystem_spec.js +11 -6
- package/test/spec/modules/mediasquareBidAdapter_spec.js +3 -0
- package/test/spec/modules/onetagBidAdapter_spec.js +81 -75
- package/test/spec/modules/orbidderBidAdapter_spec.js +6 -3
- package/test/spec/modules/oxxionRtdProvider_spec.js +113 -1
- package/test/spec/modules/relaidoBidAdapter_spec.js +4 -3
- package/test/spec/modules/tripleliftBidAdapter_spec.js +20 -1
- package/test/spec/modules/ucfunnelBidAdapter_spec.js +37 -16
- package/test/spec/modules/userId_spec.js +393 -6
|
@@ -0,0 +1,233 @@
|
|
|
1
|
+
import {cmpClient} from '../../../../libraries/cmp/cmpClient.js';
|
|
2
|
+
|
|
3
|
+
describe('cmpClient', () => {
|
|
4
|
+
function mockWindow(props = {}) {
|
|
5
|
+
let listeners = [];
|
|
6
|
+
const win = {
|
|
7
|
+
addEventListener: sinon.stub().callsFake((evt, listener) => {
|
|
8
|
+
evt === 'message' && listeners.push(listener)
|
|
9
|
+
}),
|
|
10
|
+
postMessage: sinon.stub().callsFake((msg) => {
|
|
11
|
+
listeners.forEach(ln => ln({data: msg}))
|
|
12
|
+
}),
|
|
13
|
+
...props,
|
|
14
|
+
};
|
|
15
|
+
win.top = win.parent?.top || win;
|
|
16
|
+
return win;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
it('should return undefined when there is no CMP', () => {
|
|
20
|
+
expect(cmpClient({apiName: 'missing'}, mockWindow())).to.not.exist;
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
it('should return undefined when parent is inaccessible', () => {
|
|
24
|
+
const win = mockWindow();
|
|
25
|
+
win.top = mockWindow();
|
|
26
|
+
expect(cmpClient({apiName: 'missing'}, win)).to.not.exist;
|
|
27
|
+
})
|
|
28
|
+
|
|
29
|
+
describe('direct access', () => {
|
|
30
|
+
let mockApiFn;
|
|
31
|
+
beforeEach(() => {
|
|
32
|
+
mockApiFn = sinon.stub();
|
|
33
|
+
})
|
|
34
|
+
Object.entries({
|
|
35
|
+
'on same frame': () => mockWindow({mockApiFn}),
|
|
36
|
+
'on parent frame': () => mockWindow({parent: mockWindow({parent: mockWindow({parent: mockWindow(), mockApiFn})})}),
|
|
37
|
+
}).forEach(([t, mkWindow]) => {
|
|
38
|
+
describe(t, () => {
|
|
39
|
+
let win, mkClient;
|
|
40
|
+
beforeEach(() => {
|
|
41
|
+
win = mkWindow();
|
|
42
|
+
mkClient = (opts) => cmpClient(Object.assign({apiName: 'mockApiFn'}, opts), win)
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
it('should mark client function as direct', () => {
|
|
46
|
+
expect(mkClient().isDirect).to.equal(true);
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
it('should find and call the CMP api function', () => {
|
|
50
|
+
mkClient()({command: 'mockCmd'});
|
|
51
|
+
sinon.assert.calledWith(mockApiFn, 'mockCmd');
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
describe('should return a promise that', () => {
|
|
55
|
+
let cbResult;
|
|
56
|
+
beforeEach(() => {
|
|
57
|
+
cbResult = [];
|
|
58
|
+
mockApiFn.callsFake((cmd, callback) => {
|
|
59
|
+
if (typeof callback === 'function') {
|
|
60
|
+
callback.apply(this, cbResult);
|
|
61
|
+
}
|
|
62
|
+
return 'val'
|
|
63
|
+
})
|
|
64
|
+
})
|
|
65
|
+
Object.entries({
|
|
66
|
+
callback: [sinon.stub(), 'undefined', undefined],
|
|
67
|
+
'no callback': [undefined, 'api return value', 'val']
|
|
68
|
+
}).forEach(([t, [callback, tResult, expectedResult]]) => {
|
|
69
|
+
describe(`when ${t} is provided`, () => {
|
|
70
|
+
Object.entries({
|
|
71
|
+
'no success flag': undefined,
|
|
72
|
+
'success is set': true
|
|
73
|
+
}).forEach(([t, success]) => {
|
|
74
|
+
it(`resolves to ${tResult} (${t})`, (done) => {
|
|
75
|
+
cbResult = ['cbVal', success];
|
|
76
|
+
mkClient()({callback}).then((val) => {
|
|
77
|
+
expect(val).to.equal(expectedResult);
|
|
78
|
+
done();
|
|
79
|
+
})
|
|
80
|
+
})
|
|
81
|
+
});
|
|
82
|
+
})
|
|
83
|
+
});
|
|
84
|
+
|
|
85
|
+
it('rejects to undefined when callback is provided and success = false', () => {
|
|
86
|
+
cbResult = ['cbVal', false];
|
|
87
|
+
mkClient()({callback: sinon.stub()}).catch(val => {
|
|
88
|
+
expect(val).to.equal('cbVal');
|
|
89
|
+
done();
|
|
90
|
+
})
|
|
91
|
+
});
|
|
92
|
+
|
|
93
|
+
it('rejects when CMP api throws', (done) => {
|
|
94
|
+
mockApiFn.reset();
|
|
95
|
+
const e = new Error();
|
|
96
|
+
mockApiFn.throws(e);
|
|
97
|
+
mkClient()({}).catch(val => {
|
|
98
|
+
expect(val).to.equal(e);
|
|
99
|
+
done();
|
|
100
|
+
});
|
|
101
|
+
})
|
|
102
|
+
})
|
|
103
|
+
|
|
104
|
+
it('should use apiArgs to choose and order the arguments to pass to the API fn', () => {
|
|
105
|
+
mkClient({apiArgs: ['parameter', 'command']})({
|
|
106
|
+
command: 'mockCmd',
|
|
107
|
+
parameter: 'mockParam',
|
|
108
|
+
callback() {}
|
|
109
|
+
});
|
|
110
|
+
sinon.assert.calledWith(mockApiFn, 'mockParam', 'mockCmd');
|
|
111
|
+
});
|
|
112
|
+
})
|
|
113
|
+
})
|
|
114
|
+
})
|
|
115
|
+
|
|
116
|
+
describe('postMessage access', () => {
|
|
117
|
+
let messenger, win, response;
|
|
118
|
+
beforeEach(() => {
|
|
119
|
+
response = {};
|
|
120
|
+
messenger = sinon.stub().callsFake((msg) => {
|
|
121
|
+
if (msg.mockApiCall) {
|
|
122
|
+
win.postMessage({mockApiReturn: {callId: msg.mockApiCall.callId, ...response}});
|
|
123
|
+
}
|
|
124
|
+
});
|
|
125
|
+
});
|
|
126
|
+
|
|
127
|
+
function mkClient(options) {
|
|
128
|
+
return cmpClient(Object.assign({apiName: 'mockApi'}, options), win);
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
Object.entries({
|
|
132
|
+
'on same frame': () => {
|
|
133
|
+
win = mockWindow({frames: {mockApiLocator: true}});
|
|
134
|
+
win.addEventListener('message', (evt) => messenger(evt.data));
|
|
135
|
+
},
|
|
136
|
+
'on parent frame': () => {
|
|
137
|
+
win = mockWindow({parent: mockWindow({frames: {mockApiLocator: true}})})
|
|
138
|
+
win.parent.addEventListener('message', evt => messenger(evt.data))
|
|
139
|
+
}
|
|
140
|
+
}).forEach(([t, setup]) => {
|
|
141
|
+
describe(t, () => {
|
|
142
|
+
beforeEach(setup);
|
|
143
|
+
|
|
144
|
+
it('should mark client as not direct', () => {
|
|
145
|
+
expect(mkClient().isDirect).to.equal(false);
|
|
146
|
+
});
|
|
147
|
+
|
|
148
|
+
it('should find and message the CMP frame', () => {
|
|
149
|
+
mkClient()({command: 'mockCmd', parameter: 'param'});
|
|
150
|
+
sinon.assert.calledWithMatch(messenger, {
|
|
151
|
+
mockApiCall: {
|
|
152
|
+
command: 'mockCmd',
|
|
153
|
+
parameter: 'param'
|
|
154
|
+
}
|
|
155
|
+
})
|
|
156
|
+
});
|
|
157
|
+
|
|
158
|
+
it('should use apiArgs to choose what to include in the message payload', () => {
|
|
159
|
+
mkClient({apiArgs: ['command']})({
|
|
160
|
+
command: 'cmd',
|
|
161
|
+
parameter: 'param'
|
|
162
|
+
});
|
|
163
|
+
sinon.assert.calledWithMatch(messenger, sinon.match((arg) => {
|
|
164
|
+
return arg.mockApiCall.command === 'cmd' &&
|
|
165
|
+
!arg.mockApiCall.hasOwnProperty('parameter');
|
|
166
|
+
}))
|
|
167
|
+
});
|
|
168
|
+
|
|
169
|
+
it('should not include callback in the payload, but still run it on response', () => {
|
|
170
|
+
const cb = sinon.stub();
|
|
171
|
+
mkClient({apiArgs: ['command', 'callback']})({
|
|
172
|
+
command: 'cmd',
|
|
173
|
+
callback: cb
|
|
174
|
+
});
|
|
175
|
+
sinon.assert.calledWithMatch(messenger, sinon.match(arg => !arg.mockApiCall.hasOwnProperty('callback')));
|
|
176
|
+
sinon.assert.called(cb);
|
|
177
|
+
});
|
|
178
|
+
|
|
179
|
+
it('should use callbackArgs to decide what to pass to callback', () => {
|
|
180
|
+
const cb = sinon.stub();
|
|
181
|
+
response = {a: 'one', b: 'two'};
|
|
182
|
+
mkClient({callbackArgs: ['a', 'b']})({callback: cb});
|
|
183
|
+
sinon.assert.calledWith(cb, 'one', 'two');
|
|
184
|
+
})
|
|
185
|
+
|
|
186
|
+
describe('should return a promise that', () => {
|
|
187
|
+
beforeEach(() => {
|
|
188
|
+
response = {returnValue: 'val'}
|
|
189
|
+
})
|
|
190
|
+
Object.entries({
|
|
191
|
+
'callback': [sinon.stub(), 'undefined', undefined],
|
|
192
|
+
'no callback': [undefined, 'response returnValue', 'val'],
|
|
193
|
+
}).forEach(([t, [callback, tResult, expectedResult]]) => {
|
|
194
|
+
describe(`when ${t} is provided`, () => {
|
|
195
|
+
Object.entries({
|
|
196
|
+
'no success flag': {},
|
|
197
|
+
'with success flag': {success: true}
|
|
198
|
+
}).forEach(([t, resp]) => {
|
|
199
|
+
it(`resolves to ${tResult} (${t})`, () => {
|
|
200
|
+
Object.assign(response, resp);
|
|
201
|
+
mkClient()({callback}).then((val) => {
|
|
202
|
+
expect(val).to.equal(expectedResult);
|
|
203
|
+
})
|
|
204
|
+
})
|
|
205
|
+
});
|
|
206
|
+
|
|
207
|
+
it(`rejects to ${tResult} when success = false`, (done) => {
|
|
208
|
+
response.success = false;
|
|
209
|
+
mkClient()({callback}).catch((err) => {
|
|
210
|
+
expect(err).to.equal(expectedResult);
|
|
211
|
+
done();
|
|
212
|
+
});
|
|
213
|
+
});
|
|
214
|
+
})
|
|
215
|
+
});
|
|
216
|
+
});
|
|
217
|
+
|
|
218
|
+
it('should re-use callback for messages with same callId', () => {
|
|
219
|
+
messenger.reset();
|
|
220
|
+
let callId;
|
|
221
|
+
messenger.callsFake((msg) => { if (msg.mockApiCall) callId = msg.mockApiCall.callId });
|
|
222
|
+
const callback = sinon.stub();
|
|
223
|
+
mkClient()({callback});
|
|
224
|
+
expect(callId).to.exist;
|
|
225
|
+
win.postMessage({mockApiReturn: {callId, returnValue: 'a'}});
|
|
226
|
+
win.postMessage({mockApiReturn: {callId, returnValue: 'b'}});
|
|
227
|
+
sinon.assert.calledWith(callback, 'a');
|
|
228
|
+
sinon.assert.calledWith(callback, 'b');
|
|
229
|
+
})
|
|
230
|
+
});
|
|
231
|
+
});
|
|
232
|
+
});
|
|
233
|
+
});
|
|
@@ -0,0 +1,315 @@
|
|
|
1
|
+
import {mspaRule, setupRules, isTransmitUfpdConsentDenied, isTransmitGeoConsentDenied, isBasicConsentDenied, isSensitiveNoticeMissing, isConsentDenied} from '../../../../libraries/mspa/activityControls.js';
|
|
2
|
+
import {ruleRegistry} from '../../../../src/activities/rules.js';
|
|
3
|
+
describe('isBasicConsentDenied', () => {
|
|
4
|
+
const cd = {
|
|
5
|
+
// not covered, opt in to targeted, sale, and share, all notices given, opt into precise geo
|
|
6
|
+
Gpc: 0,
|
|
7
|
+
KnownChildSensitiveDataConsents: [0, 0],
|
|
8
|
+
MspaCoveredTransaction: 2,
|
|
9
|
+
MspaOptOutOptionMode: 0,
|
|
10
|
+
MspaServiceProviderMode: 0,
|
|
11
|
+
PersonalDataConsents: 0,
|
|
12
|
+
SaleOptOut: 2,
|
|
13
|
+
SaleOptOutNotice: 1,
|
|
14
|
+
SensitiveDataLimitUseNotice: 1,
|
|
15
|
+
SensitiveDataProcessing: [0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0],
|
|
16
|
+
SensitiveDataProcessingOptOutNotice: 1,
|
|
17
|
+
SharingNotice: 1,
|
|
18
|
+
SharingOptOut: 2,
|
|
19
|
+
SharingOptOutNotice: 1,
|
|
20
|
+
TargetedAdvertisingOptOut: 2,
|
|
21
|
+
TargetedAdvertisingOptOutNotice: 1,
|
|
22
|
+
Version: 1
|
|
23
|
+
};
|
|
24
|
+
it('should be false (basic consent conditions pass) with variety of notice and opt in', () => {
|
|
25
|
+
const result = isBasicConsentDenied(cd);
|
|
26
|
+
expect(result).to.equal(false);
|
|
27
|
+
});
|
|
28
|
+
it('should be true (basic consent conditions do not pass) with personal data consent set to true (invalid state)', () => {
|
|
29
|
+
cd.PersonalDataConsents = 2;
|
|
30
|
+
const result = isBasicConsentDenied(cd);
|
|
31
|
+
expect(result).to.equal(true);
|
|
32
|
+
cd.PersonalDataConsents = 0;
|
|
33
|
+
});
|
|
34
|
+
it('should be true (basic consent conditions do not pass) with sensitive opt in but no notice', () => {
|
|
35
|
+
cd.SensitiveDataLimitUseNotice = 0;
|
|
36
|
+
const result = isBasicConsentDenied(cd);
|
|
37
|
+
expect(result).to.equal(true);
|
|
38
|
+
cd.SensitiveDataLimitUseNotice = 1;
|
|
39
|
+
});
|
|
40
|
+
})
|
|
41
|
+
describe('isSensitiveNoticeMissing', () => {
|
|
42
|
+
const cd = {
|
|
43
|
+
// not covered, opt in to targeted, sale, and share, all notices given, opt into precise geo
|
|
44
|
+
Gpc: 0,
|
|
45
|
+
KnownChildSensitiveDataConsents: [0, 0],
|
|
46
|
+
MspaCoveredTransaction: 2,
|
|
47
|
+
MspaOptOutOptionMode: 0,
|
|
48
|
+
MspaServiceProviderMode: 0,
|
|
49
|
+
PersonalDataConsents: 0,
|
|
50
|
+
SaleOptOut: 2,
|
|
51
|
+
SaleOptOutNotice: 1,
|
|
52
|
+
SensitiveDataLimitUseNotice: 1,
|
|
53
|
+
SensitiveDataProcessing: [0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0],
|
|
54
|
+
SensitiveDataProcessingOptOutNotice: 1,
|
|
55
|
+
SharingNotice: 1,
|
|
56
|
+
SharingOptOut: 2,
|
|
57
|
+
SharingOptOutNotice: 1,
|
|
58
|
+
TargetedAdvertisingOptOut: 2,
|
|
59
|
+
TargetedAdvertisingOptOutNotice: 1,
|
|
60
|
+
Version: 1
|
|
61
|
+
};
|
|
62
|
+
it('should be false (sensitive notice is given or not needed) with variety of notice and opt in', () => {
|
|
63
|
+
const result = isSensitiveNoticeMissing(cd);
|
|
64
|
+
expect(result).to.equal(false);
|
|
65
|
+
});
|
|
66
|
+
it('should be true (sensitive notice is missing) with variety of notice and opt in', () => {
|
|
67
|
+
cd.SensitiveDataLimitUseNotice = 2;
|
|
68
|
+
const result = isSensitiveNoticeMissing(cd);
|
|
69
|
+
expect(result).to.equal(true);
|
|
70
|
+
cd.SensitiveDataLimitUseNotice = 1;
|
|
71
|
+
});
|
|
72
|
+
})
|
|
73
|
+
describe('isConsentDenied', () => {
|
|
74
|
+
const cd = {
|
|
75
|
+
// not covered, opt in to targeted, sale, and share, all notices given, opt into precise geo
|
|
76
|
+
Gpc: 0,
|
|
77
|
+
KnownChildSensitiveDataConsents: [0, 0],
|
|
78
|
+
MspaCoveredTransaction: 2,
|
|
79
|
+
MspaOptOutOptionMode: 0,
|
|
80
|
+
MspaServiceProviderMode: 0,
|
|
81
|
+
PersonalDataConsents: 0,
|
|
82
|
+
SaleOptOut: 2,
|
|
83
|
+
SaleOptOutNotice: 1,
|
|
84
|
+
SensitiveDataLimitUseNotice: 1,
|
|
85
|
+
SensitiveDataProcessing: [0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0],
|
|
86
|
+
SensitiveDataProcessingOptOutNotice: 1,
|
|
87
|
+
SharingNotice: 1,
|
|
88
|
+
SharingOptOut: 2,
|
|
89
|
+
SharingOptOutNotice: 1,
|
|
90
|
+
TargetedAdvertisingOptOut: 2,
|
|
91
|
+
TargetedAdvertisingOptOutNotice: 1,
|
|
92
|
+
Version: 1
|
|
93
|
+
};
|
|
94
|
+
it('should be false (consent given personalized ads / sale / share) with variety of notice and opt in', () => {
|
|
95
|
+
const result = isConsentDenied(cd);
|
|
96
|
+
expect(result).to.equal(false);
|
|
97
|
+
});
|
|
98
|
+
it('should be true (no consent) on opt out of targeted ads via TargetedAdvertisingOptOut', () => {
|
|
99
|
+
cd.TargetedAdvertisingOptOut = 1;
|
|
100
|
+
const result = isConsentDenied(cd);
|
|
101
|
+
expect(result).to.equal(true);
|
|
102
|
+
cd.TargetedAdvertisingOptOut = 2;
|
|
103
|
+
});
|
|
104
|
+
it('should be true (no consent) on opt out of targeted ads via no TargetedAdvertisingOptOutNotice', () => {
|
|
105
|
+
cd.TargetedAdvertisingOptOutNotice = 2;
|
|
106
|
+
const result = isConsentDenied(cd);
|
|
107
|
+
expect(result).to.equal(true);
|
|
108
|
+
cd.TargetedAdvertisingOptOutNotice = 1;
|
|
109
|
+
});
|
|
110
|
+
it('should be true (no consent) if TargetedAdvertisingOptOutNotice is 0 and TargetedAdvertisingOptOut is 2', () => {
|
|
111
|
+
cd.TargetedAdvertisingOptOutNotice = 0;
|
|
112
|
+
const result = isConsentDenied(cd);
|
|
113
|
+
expect(result).to.equal(true);
|
|
114
|
+
cd.TargetedAdvertisingOptOutNotice = 1;
|
|
115
|
+
});
|
|
116
|
+
})
|
|
117
|
+
describe('isTransmitUfpdConsentDenied', () => {
|
|
118
|
+
const cd = {
|
|
119
|
+
// not covered, opt in to targeted, sale, and share, all notices given, opt into precise geo
|
|
120
|
+
Gpc: 0,
|
|
121
|
+
KnownChildSensitiveDataConsents: [0, 0],
|
|
122
|
+
MspaCoveredTransaction: 2,
|
|
123
|
+
MspaOptOutOptionMode: 0,
|
|
124
|
+
MspaServiceProviderMode: 0,
|
|
125
|
+
PersonalDataConsents: 0,
|
|
126
|
+
SaleOptOut: 2,
|
|
127
|
+
SaleOptOutNotice: 1,
|
|
128
|
+
SensitiveDataLimitUseNotice: 1,
|
|
129
|
+
SensitiveDataProcessing: [0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0],
|
|
130
|
+
SensitiveDataProcessingOptOutNotice: 1,
|
|
131
|
+
SharingNotice: 1,
|
|
132
|
+
SharingOptOut: 2,
|
|
133
|
+
SharingOptOutNotice: 1,
|
|
134
|
+
TargetedAdvertisingOptOut: 2,
|
|
135
|
+
TargetedAdvertisingOptOutNotice: 1,
|
|
136
|
+
Version: 1
|
|
137
|
+
};
|
|
138
|
+
it('should be false (consent given to add ufpd) with variety of notice and opt in', () => {
|
|
139
|
+
const result = isTransmitUfpdConsentDenied(cd);
|
|
140
|
+
expect(result).to.equal(false);
|
|
141
|
+
});
|
|
142
|
+
it('should be true (consent denied to add ufpd) if no consent to process health information', () => {
|
|
143
|
+
cd.SensitiveDataProcessing[2] = 1;
|
|
144
|
+
const result = isTransmitUfpdConsentDenied(cd);
|
|
145
|
+
expect(result).to.equal(true);
|
|
146
|
+
cd.SensitiveDataProcessing[2] = 0;
|
|
147
|
+
});
|
|
148
|
+
it('should be true (consent denied to add ufpd) with consent to process biometric data, as this should not be on openrtb', () => {
|
|
149
|
+
cd.SensitiveDataProcessing[6] = 1;
|
|
150
|
+
const result = isTransmitUfpdConsentDenied(cd);
|
|
151
|
+
expect(result).to.equal(true);
|
|
152
|
+
cd.SensitiveDataProcessing[6] = 1;
|
|
153
|
+
});
|
|
154
|
+
it('should be true (consent denied to add ufpd) without sharing notice', () => {
|
|
155
|
+
cd.SharingNotice = 2;
|
|
156
|
+
const result = isTransmitUfpdConsentDenied(cd);
|
|
157
|
+
expect(result).to.equal(true);
|
|
158
|
+
cd.SharingNotice = 1;
|
|
159
|
+
});
|
|
160
|
+
it('should be true (consent denied to add ufpd) with sale opt out', () => {
|
|
161
|
+
cd.SaleOptOut = 1;
|
|
162
|
+
const result = isTransmitUfpdConsentDenied(cd);
|
|
163
|
+
expect(result).to.equal(true);
|
|
164
|
+
cd.SaleOptOut = 2;
|
|
165
|
+
});
|
|
166
|
+
it('should be true (consent denied to add ufpd) without targeted ads opt out', () => {
|
|
167
|
+
cd.TargetedAdvertisingOptOut = 1;
|
|
168
|
+
const result = isTransmitUfpdConsentDenied(cd);
|
|
169
|
+
expect(result).to.equal(true);
|
|
170
|
+
cd.TargetedAdvertisingOptOut = 2;
|
|
171
|
+
});
|
|
172
|
+
it('should be true (consent denied to add ufpd) with missing sensitive data limit notice', () => {
|
|
173
|
+
cd.SensitiveDataLimitUseNotice = 2;
|
|
174
|
+
const result = isTransmitUfpdConsentDenied(cd);
|
|
175
|
+
expect(result).to.equal(true);
|
|
176
|
+
cd.SensitiveDataLimitUseNotice = 1;
|
|
177
|
+
});
|
|
178
|
+
})
|
|
179
|
+
|
|
180
|
+
describe('isTransmitGeoConsentDenied', () => {
|
|
181
|
+
const cd = {
|
|
182
|
+
// not covered, opt out of geo
|
|
183
|
+
Gpc: 0,
|
|
184
|
+
KnownChildSensitiveDataConsents: [0, 0],
|
|
185
|
+
MspaCoveredTransaction: 2,
|
|
186
|
+
MspaOptOutOptionMode: 0,
|
|
187
|
+
MspaServiceProviderMode: 0,
|
|
188
|
+
PersonalDataConsents: 0,
|
|
189
|
+
SaleOptOut: 2,
|
|
190
|
+
SaleOptOutNotice: 1,
|
|
191
|
+
SensitiveDataLimitUseNotice: 1,
|
|
192
|
+
SensitiveDataProcessing: [0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0],
|
|
193
|
+
SensitiveDataProcessingOptOutNotice: 1,
|
|
194
|
+
SharingNotice: 1,
|
|
195
|
+
SharingOptOut: 2,
|
|
196
|
+
SharingOptOutNotice: 1,
|
|
197
|
+
TargetedAdvertisingOptOut: 2,
|
|
198
|
+
TargetedAdvertisingOptOutNotice: 1,
|
|
199
|
+
Version: 1
|
|
200
|
+
};
|
|
201
|
+
it('should be true (consent denied to add precise geo) -- sensitive flag denied', () => {
|
|
202
|
+
const result = isTransmitGeoConsentDenied(cd);
|
|
203
|
+
expect(result).to.equal(true);
|
|
204
|
+
});
|
|
205
|
+
it('should be true (consent denied to add precise geo) -- sensitive data limit usage not given', () => {
|
|
206
|
+
cd.SensitiveDataLimitUseNotice = 0;
|
|
207
|
+
const result = isTransmitGeoConsentDenied(cd);
|
|
208
|
+
expect(result).to.equal(true);
|
|
209
|
+
cd.SensitiveDataLimitUseNotice = 1;
|
|
210
|
+
});
|
|
211
|
+
it('should be false (consent given to add precise geo) -- sensitive position 8 (index 7) is true', () => {
|
|
212
|
+
cd.SensitiveDataProcessing[7] = 2;
|
|
213
|
+
const result = isTransmitGeoConsentDenied(cd);
|
|
214
|
+
expect(result).to.equal(false);
|
|
215
|
+
cd.SensitiveDataProcessing[7] = 1;
|
|
216
|
+
});
|
|
217
|
+
})
|
|
218
|
+
|
|
219
|
+
describe('mspaRule', () => {
|
|
220
|
+
it('does not apply if SID is not applicable', () => {
|
|
221
|
+
const rule = mspaRule([1, 2], () => null, () => true, () => [3, 4]);
|
|
222
|
+
expect(rule()).to.not.exist;
|
|
223
|
+
});
|
|
224
|
+
|
|
225
|
+
it('does not apply when no SID is applicable', () => {
|
|
226
|
+
const rule = mspaRule([1], () => null, () => true, () => []);
|
|
227
|
+
expect(rule()).to.not.exist;
|
|
228
|
+
});
|
|
229
|
+
|
|
230
|
+
describe('when SID is applicable', () => {
|
|
231
|
+
let consent, denies;
|
|
232
|
+
function mkRule() {
|
|
233
|
+
return mspaRule([1, 2], () => consent, denies, () => [2])
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
beforeEach(() => {
|
|
237
|
+
consent = null;
|
|
238
|
+
denies = sinon.stub();
|
|
239
|
+
});
|
|
240
|
+
|
|
241
|
+
it('should deny when no consent is available', () => {
|
|
242
|
+
expect(mkRule()().allow).to.equal(false);
|
|
243
|
+
});
|
|
244
|
+
|
|
245
|
+
Object.entries({
|
|
246
|
+
'denies': true,
|
|
247
|
+
'allows': false
|
|
248
|
+
}).forEach(([t, denied]) => {
|
|
249
|
+
it(`should check if deny fn ${t}`, () => {
|
|
250
|
+
denies.returns(denied);
|
|
251
|
+
consent = {mock: 'value'};
|
|
252
|
+
const result = mkRule()();
|
|
253
|
+
sinon.assert.calledWith(denies, consent);
|
|
254
|
+
if (denied) {
|
|
255
|
+
expect(result.allow).to.equal(false);
|
|
256
|
+
} else {
|
|
257
|
+
expect(result).to.not.exist;
|
|
258
|
+
}
|
|
259
|
+
})
|
|
260
|
+
})
|
|
261
|
+
})
|
|
262
|
+
});
|
|
263
|
+
|
|
264
|
+
describe('setupRules', () => {
|
|
265
|
+
let rules, registerRule, isAllowed, consent;
|
|
266
|
+
beforeEach(() => {
|
|
267
|
+
rules = {
|
|
268
|
+
mockActivity: sinon.stub().returns(true)
|
|
269
|
+
};
|
|
270
|
+
([registerRule, isAllowed] = ruleRegistry());
|
|
271
|
+
consent = {
|
|
272
|
+
applicableSections: [1],
|
|
273
|
+
sectionData: {
|
|
274
|
+
mockApi: {
|
|
275
|
+
mock: 'consent'
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
};
|
|
279
|
+
});
|
|
280
|
+
|
|
281
|
+
function runSetup(api, sids, normalize) {
|
|
282
|
+
return setupRules(api, sids, normalize, rules, registerRule, () => consent)
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
it('should use section data for the given api', () => {
|
|
286
|
+
runSetup('mockApi', [1]);
|
|
287
|
+
expect(isAllowed('mockActivity', {})).to.equal(false);
|
|
288
|
+
sinon.assert.calledWith(rules.mockActivity, {mock: 'consent'})
|
|
289
|
+
});
|
|
290
|
+
|
|
291
|
+
it('should not choke when no consent data is available', () => {
|
|
292
|
+
consent = null;
|
|
293
|
+
runSetup('mockApi', [1]);
|
|
294
|
+
expect(isAllowed('mockActivity', {})).to.equal(true);
|
|
295
|
+
});
|
|
296
|
+
|
|
297
|
+
it('should check applicableSections against given SIDs', () => {
|
|
298
|
+
runSetup('mockApi', [2]);
|
|
299
|
+
expect(isAllowed('mockActivity', {})).to.equal(true);
|
|
300
|
+
});
|
|
301
|
+
|
|
302
|
+
it('should pass consent through normalizeConsent', () => {
|
|
303
|
+
const normalize = sinon.stub().returns({normalized: 'consent'})
|
|
304
|
+
runSetup('mockApi', [1], normalize);
|
|
305
|
+
expect(isAllowed('mockActivity', {})).to.equal(false);
|
|
306
|
+
sinon.assert.calledWith(normalize, {mock: 'consent'});
|
|
307
|
+
sinon.assert.calledWith(rules.mockActivity, {normalized: 'consent'});
|
|
308
|
+
});
|
|
309
|
+
|
|
310
|
+
it('should return a function that unregisters activity controls', () => {
|
|
311
|
+
const dereg = runSetup('mockApi', [1]);
|
|
312
|
+
dereg();
|
|
313
|
+
expect(isAllowed('mockActivity', {})).to.equal(true);
|
|
314
|
+
});
|
|
315
|
+
})
|
|
@@ -106,8 +106,11 @@ describe('AdmanAdapter', function () {
|
|
|
106
106
|
let placements = data['placements'];
|
|
107
107
|
for (let i = 0; i < placements.length; i++) {
|
|
108
108
|
let placement = placements[i];
|
|
109
|
-
expect(placement).to.have.all.keys('placementId', 'eids', 'bidId', 'traffic', 'sizes', 'schain', 'bidFloor');
|
|
109
|
+
expect(placement).to.have.all.keys('placementId', 'eids', 'bidId', 'traffic', 'sizes', 'schain', 'bidFloor', 'ext');
|
|
110
110
|
expect(placement.schain).to.be.an('object')
|
|
111
|
+
expect(placement.ext).to.be.an('object')
|
|
112
|
+
expect(placement.ext).to.have.key('tid')
|
|
113
|
+
expect(placement.ext.tid).to.equal(bidBanner.transactionId);
|
|
111
114
|
expect(placement.placementId).to.be.a('number');
|
|
112
115
|
expect(placement.bidId).to.be.a('string');
|
|
113
116
|
expect(placement.traffic).to.be.a('string');
|
|
@@ -132,7 +135,10 @@ describe('AdmanAdapter', function () {
|
|
|
132
135
|
let placement = placements[i];
|
|
133
136
|
expect(placement).to.have.all.keys('placementId', 'eids', 'bidId', 'traffic', 'schain', 'bidFloor',
|
|
134
137
|
'playerSize', 'minduration', 'maxduration', 'mimes', 'protocols', 'startdelay', 'placement', 'skip',
|
|
135
|
-
'skipafter', 'minbitrate', 'maxbitrate', 'delivery', 'playbackmethod', 'api', 'linearity');
|
|
138
|
+
'skipafter', 'minbitrate', 'maxbitrate', 'delivery', 'playbackmethod', 'api', 'linearity', 'ext');
|
|
139
|
+
expect(placement.ext).to.be.an('object')
|
|
140
|
+
expect(placement.ext).to.have.key('tid')
|
|
141
|
+
expect(placement.ext.tid).to.equal(bidBanner.transactionId);
|
|
136
142
|
expect(placement.schain).to.be.an('object')
|
|
137
143
|
expect(placement.placementId).to.be.a('number');
|
|
138
144
|
expect(placement.bidId).to.be.a('string');
|
|
@@ -80,7 +80,11 @@ describe('adqueryBidAdapter', function () {
|
|
|
80
80
|
})
|
|
81
81
|
|
|
82
82
|
describe('buildRequests', function () {
|
|
83
|
-
let req
|
|
83
|
+
let req;
|
|
84
|
+
beforeEach(() => {
|
|
85
|
+
req = spec.buildRequests([ bidRequest ], { refererInfo: { } })[0]
|
|
86
|
+
})
|
|
87
|
+
|
|
84
88
|
let rdata
|
|
85
89
|
|
|
86
90
|
it('should return request object', function () {
|