prebid.js 8.1.0 → 8.3.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.
Files changed (214) hide show
  1. package/.devcontainer/devcontainer.json +3 -1
  2. package/dist/33acrossBidAdapter.js +1 -1
  3. package/dist/33acrossIdSystem.js +1 -1
  4. package/dist/adagioBidAdapter.js +1 -1
  5. package/dist/adbookpspBidAdapter.js +1 -1
  6. package/dist/adgenerationBidAdapter.js +1 -1
  7. package/dist/admanBidAdapter.js +1 -1
  8. package/dist/adqueryBidAdapter.js +1 -1
  9. package/dist/adrelevantisBidAdapter.js +1 -1
  10. package/dist/adtelligentBidAdapter.js +1 -1
  11. package/dist/adtrgtmeBidAdapter.js +1 -1
  12. package/dist/adxcgBidAdapter.js +1 -1
  13. package/dist/adyoulikeBidAdapter.js +1 -1
  14. package/dist/ajaBidAdapter.js +1 -1
  15. package/dist/amxBidAdapter.js +1 -1
  16. package/dist/amxIdSystem.js +1 -1
  17. package/dist/appierAnalyticsAdapter.js +1 -1
  18. package/dist/appnexusBidAdapter.js +1 -1
  19. package/dist/asoBidAdapter.js +1 -1
  20. package/dist/axonixBidAdapter.js +1 -1
  21. package/dist/beopBidAdapter.js +1 -1
  22. package/dist/bidglassBidAdapter.js +1 -1
  23. package/dist/big-richmediaBidAdapter.js +1 -1
  24. package/dist/bridBidAdapter.js +1 -0
  25. package/dist/bridgewellBidAdapter.js +1 -1
  26. package/dist/brightMountainMediaBidAdapter.js +1 -1
  27. package/dist/carodaBidAdapter.js +1 -1
  28. package/dist/categoryTranslation.js +1 -1
  29. package/dist/chtnwBidAdapter.js +1 -1
  30. package/dist/cmp.js +1 -0
  31. package/dist/concertBidAdapter.js +1 -1
  32. package/dist/connectadBidAdapter.js +1 -1
  33. package/dist/consentManagement.js +1 -1
  34. package/dist/consentManagementGpp.js +1 -1
  35. package/dist/consentManagementUsp.js +1 -1
  36. package/dist/consumableBidAdapter.js +1 -1
  37. package/dist/conversantAnalyticsAdapter.js +1 -1
  38. package/dist/conversantBidAdapter.js +1 -1
  39. package/dist/craftBidAdapter.js +1 -1
  40. package/dist/criteoBidAdapter.js +1 -1
  41. package/dist/cwireBidAdapter.js +1 -1
  42. package/dist/dependencies.json +15 -0
  43. package/dist/discoveryBidAdapter.js +1 -1
  44. package/dist/dspxBidAdapter.js +1 -1
  45. package/dist/eplanningBidAdapter.js +1 -1
  46. package/dist/euidIdSystem.js +1 -1
  47. package/dist/feedadBidAdapter.js +1 -1
  48. package/dist/finativeBidAdapter.js +1 -1
  49. package/dist/freewheel-sspBidAdapter.js +1 -1
  50. package/dist/gmosspBidAdapter.js +1 -1
  51. package/dist/goldbachBidAdapter.js +1 -1
  52. package/dist/gppControl_usnat.js +1 -0
  53. package/dist/greenbidsAnalyticsAdapter.js +1 -1
  54. package/dist/greenbidsRtdProvider.js +1 -1
  55. package/dist/gridBidAdapter.js +1 -1
  56. package/dist/gumgumBidAdapter.js +1 -1
  57. package/dist/h12mediaBidAdapter.js +1 -1
  58. package/dist/holidBidAdapter.js +1 -1
  59. package/dist/hypelabBidAdapter.js +1 -1
  60. package/dist/id5IdSystem.js +1 -1
  61. package/dist/imdsBidAdapter.js +1 -1
  62. package/dist/improvedigitalBidAdapter.js +1 -1
  63. package/dist/insticatorBidAdapter.js +1 -1
  64. package/dist/intentIqIdSystem.js +1 -1
  65. package/dist/ixBidAdapter.js +1 -1
  66. package/dist/justpremiumBidAdapter.js +1 -1
  67. package/dist/kargoBidAdapter.js +1 -1
  68. package/dist/konduitAnalyticsAdapter.js +1 -1
  69. package/dist/kueezBidAdapter.js +1 -1
  70. package/dist/kueezRtbBidAdapter.js +1 -1
  71. package/dist/kulturemediaBidAdapter.js +1 -1
  72. package/dist/lassoBidAdapter.js +1 -1
  73. package/dist/lifestreetBidAdapter.js +1 -1
  74. package/dist/liveIntentIdSystem.js +1 -1
  75. package/dist/livewrappedAnalyticsAdapter.js +1 -1
  76. package/dist/logicadBidAdapter.js +1 -1
  77. package/dist/loglyliftBidAdapter.js +1 -1
  78. package/dist/magniteAnalyticsAdapter.js +1 -1
  79. package/dist/malltvAnalyticsAdapter.js +1 -1
  80. package/dist/marsmediaBidAdapter.js +1 -1
  81. package/dist/mediafuseBidAdapter.js +1 -1
  82. package/dist/mediagoBidAdapter.js +1 -1
  83. package/dist/mediasquareBidAdapter.js +1 -1
  84. package/dist/mgidBidAdapter.js +1 -1
  85. package/dist/minutemediaBidAdapter.js +1 -1
  86. package/dist/minutemediaplusBidAdapter.js +1 -1
  87. package/dist/mspa.js +1 -0
  88. package/dist/nexx360BidAdapter.js +1 -1
  89. package/dist/not-for-prod/prebid.js +144 -140
  90. package/dist/oguryBidAdapter.js +1 -1
  91. package/dist/onetagBidAdapter.js +1 -1
  92. package/dist/ooloAnalyticsAdapter.js +1 -1
  93. package/dist/optidigitalBidAdapter.js +1 -1
  94. package/dist/outbrainBidAdapter.js +1 -1
  95. package/dist/oxxionRtdProvider.js +1 -1
  96. package/dist/parrableIdSystem.js +1 -1
  97. package/dist/pixfutureBidAdapter.js +1 -1
  98. package/dist/prebid-core.js +1 -1
  99. package/dist/publinkIdSystem.js +1 -1
  100. package/dist/pubmaticBidAdapter.js +1 -1
  101. package/dist/pubwiseAnalyticsAdapter.js +1 -1
  102. package/dist/pxyzBidAdapter.js +1 -1
  103. package/dist/quantcastBidAdapter.js +1 -1
  104. package/dist/readpeakBidAdapter.js +1 -1
  105. package/dist/relaidoBidAdapter.js +1 -1
  106. package/dist/retailspotBidAdapter.js +1 -1
  107. package/dist/rhythmoneBidAdapter.js +1 -1
  108. package/dist/riseBidAdapter.js +1 -1
  109. package/dist/rubiconBidAdapter.js +1 -1
  110. package/dist/seedingAllianceBidAdapter.js +1 -1
  111. package/dist/seedtagBidAdapter.js +1 -1
  112. package/dist/sharethroughAnalyticsAdapter.js +1 -1
  113. package/dist/sharethroughBidAdapter.js +1 -1
  114. package/dist/shinezBidAdapter.js +1 -1
  115. package/dist/smaatoBidAdapter.js +1 -1
  116. package/dist/smartadserverBidAdapter.js +1 -1
  117. package/dist/smartxBidAdapter.js +1 -1
  118. package/dist/smartyadsBidAdapter.js +1 -1
  119. package/dist/smilewantedBidAdapter.js +1 -1
  120. package/dist/sonobiBidAdapter.js +1 -1
  121. package/dist/sovrnAnalyticsAdapter.js +1 -1
  122. package/dist/sovrnBidAdapter.js +1 -1
  123. package/dist/sspBCBidAdapter.js +1 -1
  124. package/dist/stvBidAdapter.js +1 -1
  125. package/dist/sublimeBidAdapter.js +1 -1
  126. package/dist/targetVideoBidAdapter.js +1 -1
  127. package/dist/teadsBidAdapter.js +1 -1
  128. package/dist/trafficgateBidAdapter.js +1 -1
  129. package/dist/trionBidAdapter.js +1 -1
  130. package/dist/tripleliftBidAdapter.js +1 -1
  131. package/dist/ttdBidAdapter.js +1 -1
  132. package/dist/ucfunnelAnalyticsAdapter.js +1 -1
  133. package/dist/uid2IdSystem.js +1 -1
  134. package/dist/underdogmediaBidAdapter.js +1 -1
  135. package/dist/undertoneBidAdapter.js +1 -1
  136. package/dist/userId.js +1 -1
  137. package/dist/vidazooBidAdapter.js +1 -1
  138. package/dist/videobyteBidAdapter.js +1 -1
  139. package/dist/visxBidAdapter.js +1 -1
  140. package/dist/vuukleBidAdapter.js +1 -1
  141. package/dist/widespaceBidAdapter.js +1 -1
  142. package/dist/winrBidAdapter.js +1 -1
  143. package/dist/yahoosspBidAdapter.js +1 -1
  144. package/dist/yieldmoBidAdapter.js +1 -1
  145. package/dist/yieldoneAnalyticsAdapter.js +1 -1
  146. package/libraries/cmp/cmpClient.js +139 -0
  147. package/libraries/mspa/activityControls.js +91 -0
  148. package/modules/adagioBidAdapter.js +2 -1
  149. package/modules/admanBidAdapter.js +5 -0
  150. package/modules/adtelligentBidAdapter.js +8 -0
  151. package/modules/beopBidAdapter.js +6 -6
  152. package/modules/beopBidAdapter.md +35 -1
  153. package/modules/bridBidAdapter.js +223 -0
  154. package/modules/cadentApertureMXBidAdapter.md +2 -2
  155. package/modules/categoryTranslation.js +3 -2
  156. package/modules/consentManagement.js +12 -86
  157. package/modules/consentManagementGpp.js +47 -126
  158. package/modules/consentManagementUsp.js +19 -97
  159. package/modules/discoveryBidAdapter.js +1 -1
  160. package/modules/gppControl_usnat.js +11 -0
  161. package/modules/holidBidAdapter.js +49 -30
  162. package/modules/intentIqIdSystem.js +6 -5
  163. package/modules/ixBidAdapter.js +2 -1
  164. package/modules/liveIntentIdSystem.js +8 -3
  165. package/modules/livewrappedAnalyticsAdapter.js +33 -33
  166. package/modules/mediagoBidAdapter.js +1 -0
  167. package/modules/mediasquareBidAdapter.js +19 -23
  168. package/modules/oxxionRtdProvider.js +124 -11
  169. package/modules/oxxionRtdProvider.md +19 -4
  170. package/modules/smartyadsBidAdapter.js +6 -3
  171. package/modules/sovrnBidAdapter.js +5 -0
  172. package/modules/trafficgateBidAdapter.js +126 -72
  173. package/modules/tripleliftBidAdapter.js +21 -1
  174. package/modules/userId/eids.js +29 -0
  175. package/modules/userId/eids.md +19 -2
  176. package/modules/userId/index.js +78 -29
  177. package/modules/userId/userId.md +3 -0
  178. package/modules/vidazooBidAdapter.js +68 -16
  179. package/package.json +1 -1
  180. package/src/activities/params.js +4 -1
  181. package/test/spec/libraries/cmp/cmpClient_spec.js +233 -0
  182. package/test/spec/libraries/mspa/activityControls_spec.js +315 -0
  183. package/test/spec/modules/adagioBidAdapter_spec.js +2 -1
  184. package/test/spec/modules/admanBidAdapter_spec.js +8 -2
  185. package/test/spec/modules/adqueryBidAdapter_spec.js +5 -1
  186. package/test/spec/modules/adtelligentBidAdapter_spec.js +8 -0
  187. package/test/spec/modules/beopBidAdapter_spec.js +18 -2
  188. package/test/spec/modules/bridBidAdapter_spec.js +129 -0
  189. package/test/spec/modules/byDataAnalyticsAdapter_spec.js +9 -7
  190. package/test/spec/modules/cadentApertureMXBidAdapter_spec.js +1 -1
  191. package/test/spec/modules/chtnwBidAdapter_spec.js +4 -1
  192. package/test/spec/modules/consentManagementGpp_spec.js +84 -7
  193. package/test/spec/modules/consentManagement_spec.js +8 -18
  194. package/test/spec/modules/datablocksBidAdapter_spec.js +7 -3
  195. package/test/spec/modules/eids_spec.js +87 -0
  196. package/test/spec/modules/holidBidAdapter_spec.js +26 -6
  197. package/test/spec/modules/insticatorBidAdapter_spec.js +6 -2
  198. package/test/spec/modules/intentIqIdSystem_spec.js +36 -2
  199. package/test/spec/modules/ixBidAdapter_spec.js +52 -18
  200. package/test/spec/modules/lassoBidAdapter_spec.js +6 -4
  201. package/test/spec/modules/liveIntentIdMinimalSystem_spec.js +17 -2
  202. package/test/spec/modules/liveIntentIdSystem_spec.js +11 -6
  203. package/test/spec/modules/mediasquareBidAdapter_spec.js +3 -0
  204. package/test/spec/modules/onetagBidAdapter_spec.js +81 -75
  205. package/test/spec/modules/orbidderBidAdapter_spec.js +6 -3
  206. package/test/spec/modules/oxxionRtdProvider_spec.js +113 -1
  207. package/test/spec/modules/relaidoBidAdapter_spec.js +4 -3
  208. package/test/spec/modules/smartyadsBidAdapter_spec.js +1 -1
  209. package/test/spec/modules/sovrnBidAdapter_spec.js +34 -0
  210. package/test/spec/modules/trafficgateBidAdapter_spec.js +1349 -199
  211. package/test/spec/modules/tripleliftBidAdapter_spec.js +20 -1
  212. package/test/spec/modules/ucfunnelBidAdapter_spec.js +37 -16
  213. package/test/spec/modules/userId_spec.js +393 -6
  214. package/test/spec/modules/vidazooBidAdapter_spec.js +131 -0
@@ -1,4 +1,4 @@
1
- import {_each, deepAccess, parseSizesInput, parseUrl, uniques, isFn} from '../src/utils.js';
1
+ import {_each, chunk, deepAccess, isFn, parseSizesInput, parseUrl, uniques, isArray} from '../src/utils.js';
2
2
  import {registerBidder} from '../src/adapters/bidderFactory.js';
3
3
  import {BANNER, VIDEO} from '../src/mediaTypes.js';
4
4
  import {getStorageManager} from '../src/storageManager.js';
@@ -48,7 +48,7 @@ function isBidRequestValid(bid) {
48
48
  return !!(extractCID(params) && extractPID(params));
49
49
  }
50
50
 
51
- function buildRequest(bid, topWindowUrl, sizes, bidderRequest, bidderTimeout) {
51
+ function buildRequestData(bid, topWindowUrl, sizes, bidderRequest, bidderTimeout) {
52
52
  const {
53
53
  params,
54
54
  bidId,
@@ -69,9 +69,7 @@ function buildRequest(bid, topWindowUrl, sizes, bidderRequest, bidderTimeout) {
69
69
  const dealId = getNextDealId(hashUrl);
70
70
  const uniqueDealId = getUniqueDealId(hashUrl);
71
71
  const sId = getVidazooSessionId();
72
- const cId = extractCID(params);
73
72
  const pId = extractPID(params);
74
- const subDomain = extractSubDomain(params);
75
73
  const ptrace = getCacheOpt();
76
74
  const isStorageAllowed = bidderSettings.get(BIDDER_CODE, 'storageAllowed');
77
75
 
@@ -153,17 +151,46 @@ function buildRequest(bid, topWindowUrl, sizes, bidderRequest, bidderTimeout) {
153
151
  data.gppSid = bidderRequest.ortb2.regs.gpp_sid;
154
152
  }
155
153
 
154
+ _each(ext, (value, key) => {
155
+ data['ext.' + key] = value;
156
+ });
157
+
158
+ return data;
159
+ }
160
+
161
+ function buildRequest(bid, topWindowUrl, sizes, bidderRequest, bidderTimeout) {
162
+ const {params} = bid;
163
+ const cId = extractCID(params);
164
+ const subDomain = extractSubDomain(params);
165
+ const data = buildRequestData(bid, topWindowUrl, sizes, bidderRequest, bidderTimeout);
156
166
  const dto = {
157
167
  method: 'POST',
158
168
  url: `${createDomain(subDomain)}/prebid/multi/${cId}`,
159
169
  data: data
160
170
  };
171
+ return dto;
172
+ }
161
173
 
162
- _each(ext, (value, key) => {
163
- dto.data['ext.' + key] = value;
174
+ function buildSingleRequest(bidRequests, bidderRequest, topWindowUrl, bidderTimeout) {
175
+ const {params} = bidRequests[0];
176
+ const cId = extractCID(params);
177
+ const subDomain = extractSubDomain(params);
178
+ const data = bidRequests.map(bid => {
179
+ const sizes = parseSizesInput(bid.sizes);
180
+ return buildRequestData(bid, topWindowUrl, sizes, bidderRequest, bidderTimeout)
181
+ });
182
+ const CHUNK_SIZE = Math.min(10, config.getConfig('vidazoo.chunkSize') || 10);
183
+
184
+ const chunkedData = chunk(data, CHUNK_SIZE);
185
+ return chunkedData.map(chunk => {
186
+ return {
187
+ method: 'POST',
188
+ url: `${createDomain(subDomain)}/prebid/multi/${cId}`,
189
+ data: {
190
+ bids: chunk
191
+ }
192
+ };
164
193
  });
165
-
166
- return dto;
167
194
  }
168
195
 
169
196
  function appendUserIdsToRequestPayload(payloadRef, userIds) {
@@ -193,12 +220,33 @@ function buildRequests(validBidRequests, bidderRequest) {
193
220
  // TODO: does the fallback make sense here?
194
221
  const topWindowUrl = bidderRequest.refererInfo.page || bidderRequest.refererInfo.topmostLocation;
195
222
  const bidderTimeout = config.getConfig('bidderTimeout');
223
+
224
+ const singleRequestMode = config.getConfig('vidazoo.singleRequest');
225
+
196
226
  const requests = [];
197
- validBidRequests.forEach(validBidRequest => {
198
- const sizes = parseSizesInput(validBidRequest.sizes);
199
- const request = buildRequest(validBidRequest, topWindowUrl, sizes, bidderRequest, bidderTimeout);
200
- requests.push(request);
201
- });
227
+
228
+ if (singleRequestMode) {
229
+ // We need to split the requests into banner and video requests
230
+ const bannerBidRequests = validBidRequests.filter(bid => isArray(bid.mediaTypes) ? bid.mediaTypes.includes(BANNER) : bid.mediaTypes[BANNER] !== undefined);
231
+ if (bannerBidRequests.length > 0) {
232
+ const singleRequests = buildSingleRequest(bannerBidRequests, bidderRequest, topWindowUrl, bidderTimeout);
233
+ requests.push(...singleRequests);
234
+ }
235
+
236
+ // Video Logic
237
+ const videoBidRequests = validBidRequests.filter(bid => bid.mediaTypes[VIDEO] !== undefined);
238
+ videoBidRequests.forEach(validBidRequest => {
239
+ const sizes = parseSizesInput(validBidRequest.sizes);
240
+ const request = buildRequest(validBidRequest, topWindowUrl, sizes, bidderRequest, bidderTimeout);
241
+ requests.push(request);
242
+ });
243
+ } else {
244
+ validBidRequests.forEach(validBidRequest => {
245
+ const sizes = parseSizesInput(validBidRequest.sizes);
246
+ const request = buildRequest(validBidRequest, topWindowUrl, sizes, bidderRequest, bidderTimeout);
247
+ requests.push(request);
248
+ });
249
+ }
202
250
  return requests;
203
251
  }
204
252
 
@@ -206,13 +254,15 @@ function interpretResponse(serverResponse, request) {
206
254
  if (!serverResponse || !serverResponse.body) {
207
255
  return [];
208
256
  }
209
- const {bidId} = request.data;
257
+
258
+ const singleRequestMode = config.getConfig('vidazoo.singleRequest');
259
+ const reqBidId = deepAccess(request, 'data.bidId');
210
260
  const {results} = serverResponse.body;
211
261
 
212
262
  let output = [];
213
263
 
214
264
  try {
215
- results.forEach(result => {
265
+ results.forEach((result, i) => {
216
266
  const {
217
267
  creativeId,
218
268
  ad,
@@ -221,6 +271,7 @@ function interpretResponse(serverResponse, request) {
221
271
  width,
222
272
  height,
223
273
  currency,
274
+ bidId,
224
275
  advertiserDomains,
225
276
  metaData,
226
277
  mediaType = BANNER
@@ -230,7 +281,7 @@ function interpretResponse(serverResponse, request) {
230
281
  }
231
282
 
232
283
  const response = {
233
- requestId: bidId,
284
+ requestId: (singleRequestMode && bidId) ? bidId : reqBidId,
234
285
  cpm: price,
235
286
  width: width,
236
287
  height: height,
@@ -264,6 +315,7 @@ function interpretResponse(serverResponse, request) {
264
315
  }
265
316
  output.push(response);
266
317
  });
318
+
267
319
  return output;
268
320
  } catch (e) {
269
321
  return [];
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "prebid.js",
3
- "version": "8.1.0",
3
+ "version": "8.3.0",
4
4
  "description": "Header Bidding Management Library",
5
5
  "main": "src/prebid.js",
6
6
  "scripts": {
@@ -1,4 +1,5 @@
1
1
  import {MODULE_TYPE_BIDDER} from './modules.js';
2
+ import {hook} from '../hook.js';
2
3
 
3
4
  /**
4
5
  * Component ID - who is trying to perform the activity?
@@ -54,6 +55,8 @@ export function activityParamsBuilder(resolveAlias) {
54
55
  if (moduleType === MODULE_TYPE_BIDDER) {
55
56
  defaults[ACTIVITY_PARAM_ADAPTER_CODE] = resolveAlias(moduleName);
56
57
  }
57
- return Object.assign(defaults, params);
58
+ return buildActivityParams(Object.assign(defaults, params));
58
59
  }
59
60
  }
61
+
62
+ export const buildActivityParams = hook('sync', params => params);
@@ -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
+ });