prebid-universal-creative 1.14.2 → 1.16.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 (41) hide show
  1. package/.babelrc +1 -2
  2. package/.github/workflows/issue_tracker.yml +31 -16
  3. package/README.md +21 -3
  4. package/dist/amp.js +3 -0
  5. package/dist/banner.js +3 -0
  6. package/dist/creative.js +4 -3
  7. package/dist/creative.max.js +546 -593
  8. package/dist/load-cookie-with-consent.html +1 -1
  9. package/dist/load-cookie.html +1 -1
  10. package/dist/mobile.js +3 -0
  11. package/dist/native-render.js +3 -3
  12. package/dist/native-trk.js +3 -3
  13. package/dist/native.js +3 -0
  14. package/dist/uid.js +3 -3
  15. package/dist/video.js +3 -0
  16. package/gulpfile.js +84 -45
  17. package/karma.conf.maker.js +4 -6
  18. package/package.json +80 -82
  19. package/src/ampOrMobile.js +14 -0
  20. package/src/creative.js +2 -9
  21. package/src/environment.js +62 -75
  22. package/src/legacy.js +29 -0
  23. package/src/legacyNativeRender.js +6 -0
  24. package/src/mobileAndAmpRender.js +239 -0
  25. package/src/nativeAssetManager.js +91 -57
  26. package/src/nativeORTBTrackerManager.js +2 -2
  27. package/src/nativeRender.js +2 -2
  28. package/src/nativeRenderManager.js +46 -69
  29. package/src/postscribeRender.js +10 -0
  30. package/src/renderingManager.js +106 -358
  31. package/src/utils.js +1 -11
  32. package/template/amp/dfp-creative.html +1 -1
  33. package/test/spec/environment_spec.js +4 -11
  34. package/test/spec/legacyNativeRender_spec.js +25 -0
  35. package/test/spec/mobileAndAmpRender_spec.js +316 -0
  36. package/test/spec/nativeAssetManager_spec.js +227 -79
  37. package/test/spec/nativeORTBTrackerManager_spec.js +3 -19
  38. package/test/spec/nativeRenderManager_spec.js +77 -55
  39. package/test/spec/nativeRender_spec.js +23 -0
  40. package/test/spec/renderingManager_spec.js +16 -265
  41. package/webpack.conf.js +3 -1
@@ -1,8 +1,9 @@
1
- import { expect } from 'chai';
2
- import { merge } from 'lodash';
3
- import { newNativeAssetManager } from 'src/nativeAssetManager';
4
- import { mocks } from 'test/helpers/mocks';
1
+ import {expect} from 'chai';
2
+ import {merge} from 'lodash';
3
+ import {newNativeAssetManager} from 'src/nativeAssetManager';
4
+ import {mocks} from 'test/helpers/mocks';
5
5
  import * as utils from 'src/utils';
6
+ import {prebidMessenger} from '../../src/messaging.js';
6
7
 
7
8
  const ORIGIN = 'https://origin.com'
8
9
  const AD_ID = 'abc123';
@@ -12,6 +13,7 @@ const NATIVE_KEYS = {
12
13
  body: 'hb_native_body',
13
14
  body2: 'hb_native_body2',
14
15
  privacyLink: 'hb_native_privacy',
16
+ privacyIcon: 'hb_native_privicon',
15
17
  sponsoredBy: 'hb_native_brand',
16
18
  image: 'hb_native_image',
17
19
  icon: 'hb_native_icon',
@@ -39,11 +41,16 @@ const mockDocument = {
39
41
  };
40
42
 
41
43
  // creates mock postmessage response from prebid's native.js:getAssetMessage
42
- function createResponder(assets,url,template) {
44
+ function createResponder(assets,url,template, clickUrlUnesc = '') {
43
45
  return function(type, listener) {
44
46
  if (type !== 'message') { return; }
45
47
 
46
- const data = { message: 'assetResponse', adId: AD_ID, assets, adTemplate:template, rendererUrl:url };
48
+ const data = {
49
+ message: 'assetResponse',
50
+ adId: AD_ID, assets,
51
+ adTemplate:template,
52
+ rendererUrl:url,
53
+ };
47
54
  listener({ data: JSON.stringify(data), origin: ORIGIN});
48
55
  };
49
56
  }
@@ -85,8 +92,11 @@ function generateRenderer(assets) {
85
92
  describe('nativeAssetManager', () => {
86
93
  let win;
87
94
 
88
- function makeManager() {
89
- return newNativeAssetManager(win, ORIGIN);
95
+ function makeManager(args, mkMessenger = prebidMessenger) {
96
+ return newNativeAssetManager(win, {
97
+ pubUrl: ORIGIN,
98
+ ...args
99
+ }, mkMessenger);
90
100
  }
91
101
 
92
102
  beforeEach(() => {
@@ -111,10 +121,10 @@ describe('nativeAssetManager', () => {
111
121
  { key: 'body', value: 'new value' },
112
122
  { key: 'clickUrl', value: 'http://www.example.com' },
113
123
  ]);
114
-
124
+
115
125
  const nativeAssetManager = makeManager();
116
126
  nativeAssetManager.loadAssets(AD_ID);
117
-
127
+
118
128
  expect(win.document.body.innerHTML).to.include('<p>new value</p>');
119
129
  expect(win.document.body.innerHTML).to.include(`
120
130
  <a href="http://www.example.com">Click Here</a>
@@ -122,17 +132,17 @@ describe('nativeAssetManager', () => {
122
132
  // title was not a requested asset so this should stay as is
123
133
  expect(win.document.body.innerHTML).to.include('<h1>hb_native_title</h1>');
124
134
  });
125
-
135
+
126
136
  it('replaces all occurrences of the placeholder if it appears more than once', () => {
127
137
  win.document.body.innerHTML = `
128
138
  <a href="hb_native_linkurl:${AD_ID}">Click Here</a>
129
139
  <a href="hb_native_linkurl:${AD_ID}">Or Here</a>
130
140
  `;
131
141
  win.addEventListener = createResponder([{ key: 'clickUrl', value: 'http://www.example.com' }]);
132
-
142
+
133
143
  const nativeAssetManager = makeManager();
134
144
  nativeAssetManager.loadAssets(AD_ID);
135
-
145
+
136
146
  expect(win.document.body.innerHTML).to.include(`
137
147
  <a href="http://www.example.com">Click Here</a>
138
148
  `);
@@ -140,23 +150,22 @@ describe('nativeAssetManager', () => {
140
150
  <a href="http://www.example.com">Or Here</a>
141
151
  `);
142
152
  });
143
-
153
+
144
154
  it('attaches and removes message listeners', (done) => {
145
155
  win.document.body.innerHTML = `<h1>hb_native_title:${AD_ID}</h1>`;
146
156
  const responder = createResponder();
147
157
  win.addEventListener = function (evType, listener) {
148
158
  setTimeout(() => responder(evType, listener), 0);
149
159
  }
150
-
160
+
151
161
  const nativeAssetManager = makeManager();
152
162
  nativeAssetManager.loadAssets(AD_ID);
153
163
  setTimeout(() => {
154
- expect(win.parent.postMessage.callCount).to.equal(1);
155
164
  expect(win.removeEventListener.callCount).to.equal(1);
156
165
  done();
157
166
  }, 0);
158
167
  });
159
-
168
+
160
169
  it('replaces native placeholders with their asset values from adTemplate', () => {
161
170
  const html = `<script>
162
171
  let nativeTag = {};
@@ -171,7 +180,7 @@ describe('nativeAssetManager', () => {
171
180
  adId : AD_ID,
172
181
  adTemplate : '<div class=\"sponsored-post\">\r\n <div class=\"thumbnail\"><\/div>\r\n <div class=\"content\">\r\n <h1>\r\n <a href=\"##hb_native_linkurl##\" target=\"_blank\" class=\"pb-click\">##hb_native_title##<\/a>\r\n <\/h1>\r\n <p>##hb_native_body##<\/p>\r\n \t<div class=\"attribution\">\r\n \t<img class=\"pb-icon\" src=\"##hb_native_image##\" alt=\"icon\" height=\"150\" width=\"50\">\r\n \t\r\n \t<\/div>\r\n\t<\/div>\r\n<\/div>'
173
182
  };
174
-
183
+
175
184
  win.document.body.innerHTML = html;
176
185
  win.addEventListener = createResponder([
177
186
  { key: 'body', value: 'Body content' },
@@ -179,15 +188,15 @@ describe('nativeAssetManager', () => {
179
188
  { key: 'clickUrl', value: 'http://www.example.com' },
180
189
  { key: 'image', value: 'http://www.image.com/picture.jpg' },
181
190
  ]);
182
-
191
+
183
192
  const nativeAssetManager = makeManager();
184
193
  nativeAssetManager.loadAssets(AD_ID);
185
-
194
+
186
195
  expect(win.document.body.innerHTML).to.include(`<a href="http://www.example.com" target="_blank" class="pb-click">new value</a>`);
187
196
  expect(win.document.body.innerHTML).to.include(`<img class="pb-icon" src="http://www.image.com/picture.jpg" alt="icon" height="150" width="50">`);
188
197
  expect(win.document.body.innerHTML).to.include(`<p>Body content</p>`);
189
198
  });
190
-
199
+
191
200
  it('loads rendererUrl and passes assets to renderAd - writes response to innerHtml', () => {
192
201
  const html = `<script>
193
202
  let nativeTag = {};
@@ -202,25 +211,25 @@ describe('nativeAssetManager', () => {
202
211
  rendererUrl : 'https://www.renderer.com/render.js',
203
212
  requestAllAssets : true
204
213
  };
205
-
214
+
206
215
  win.document.body.innerHTML = html;
207
216
  win.renderAd = generateRenderer;
208
-
217
+
209
218
  win.addEventListener = createAllResponder([
210
219
  { key: 'body', value: 'Body content' },
211
220
  { key: 'title', value: 'new value' },
212
221
  { key: 'clickUrl', value: 'http://www.example.com' },
213
222
  { key: 'image', value: 'http://www.image.com/picture.jpg' },
214
223
  ],null,null);
215
-
224
+
216
225
  const nativeAssetManager = makeManager();
217
226
  nativeAssetManager.loadAssets(AD_ID);
218
-
227
+
219
228
  expect(win.document.body.innerHTML).to.include(`<a href="http://www.example.com" target="_blank" class="pb-click">new value</a>`);
220
229
  expect(win.document.body.innerHTML).to.include(`<img class="pb-icon" src="http://www.image.com/picture.jpg" alt="icon" height="150" width="50">`);
221
230
  expect(win.document.body.innerHTML).to.include(`<p>Body content</p>`);
222
231
  });
223
-
232
+
224
233
  it('adId does not match, so assets are not replaced', () => {
225
234
  const html = `<script>
226
235
  let nativeTag = {};
@@ -235,20 +244,20 @@ describe('nativeAssetManager', () => {
235
244
  rendererUrl : 'https://www.renderer.com/render.js',
236
245
  requestAllAssets : true
237
246
  };
238
-
247
+
239
248
  win.document.body.innerHTML = html;
240
249
  win.renderAd = generateRenderer;
241
-
250
+
242
251
  win.addEventListener = createAllResponder([
243
252
  { key: 'body', value: 'Body content' },
244
253
  { key: 'title', value: 'new value' },
245
254
  { key: 'clickUrl', value: 'http://www.example.com' },
246
255
  { key: 'image', value: 'http://www.image.com/picture.jpg' },
247
256
  ],null,null);
248
-
257
+
249
258
  const nativeAssetManager = makeManager();
250
259
  nativeAssetManager.loadAssets(AD_ID);
251
-
260
+
252
261
  expect(win.document.body.innerHTML).to.equal(`<script>
253
262
  let nativeTag = {};
254
263
  nativeTag.pubUrl = "https://www.url.com";
@@ -257,7 +266,7 @@ describe('nativeAssetManager', () => {
257
266
  window.pbNativeTag.renderNativeAd(nativeTag);
258
267
  </script>`);
259
268
  });
260
-
269
+
261
270
  it('adId does not match on first response, so assets are not replaced until match on second response', () => {
262
271
  const html = `<script>
263
272
  let nativeTag = {};
@@ -272,20 +281,20 @@ describe('nativeAssetManager', () => {
272
281
  rendererUrl : 'https://www.renderer.com/render.js',
273
282
  requestAllAssets : true
274
283
  };
275
-
284
+
276
285
  win.document.body.innerHTML = html;
277
286
  win.renderAd = generateRenderer;
278
-
287
+
279
288
  win.addEventListener = createAllResponder([
280
289
  { key: 'body', value: 'Body No Replace' },
281
290
  { key: 'title', value: 'new value no replace' },
282
291
  { key: 'clickUrl', value: 'http://www.example.com/noreplace' },
283
292
  { key: 'image', value: 'http://www.image.com/picture.jpg?noreplace=true' },
284
293
  ],null,null);
285
-
294
+
286
295
  const nativeAssetManager = makeManager();
287
296
  nativeAssetManager.loadAssets(AD_ID2);
288
-
297
+
289
298
  expect(win.document.body.innerHTML).to.equal(`<script>
290
299
  let nativeTag = {};
291
300
  nativeTag.pubUrl = "https://www.url.com";
@@ -293,21 +302,21 @@ describe('nativeAssetManager', () => {
293
302
  nativeTag.requestAllAssets = true;
294
303
  window.pbNativeTag.renderNativeAd(nativeTag);
295
304
  </script>`);
296
-
305
+
297
306
  win.addEventListener = createAltAllResponder([
298
307
  { key: 'body', value: 'Body content' },
299
308
  { key: 'title', value: 'new value' },
300
309
  { key: 'clickUrl', value: 'http://www.example.com' },
301
310
  { key: 'image', value: 'http://www.image.com/picture.jpg' },
302
311
  ],null,null);
303
-
312
+
304
313
  nativeAssetManager.loadAssets(AD_ID2);
305
-
314
+
306
315
  expect(win.document.body.innerHTML).to.include(`<a href="http://www.example.com" target="_blank" class="pb-click">new value</a>`);
307
316
  expect(win.document.body.innerHTML).to.include(`<img class="pb-icon" src="http://www.image.com/picture.jpg" alt="icon" height="150" width="50">`);
308
317
  expect(win.document.body.innerHTML).to.include(`<p>Body content</p>`);
309
318
  });
310
-
319
+
311
320
  it('no placeholders found but requests all assets flag set - rendererUrl', () => {
312
321
  const url = 'https://www.renderer.com/render.js';
313
322
  win.pbNativeData = {
@@ -316,25 +325,25 @@ describe('nativeAssetManager', () => {
316
325
  rendererUrl : 'https://www.renderer.com/render.js',
317
326
  requestAllAssets : true
318
327
  };
319
-
328
+
320
329
  win.document.body.innerHTML = '';
321
330
  win.renderAd = generateRenderer;
322
-
331
+
323
332
  win.addEventListener = createAllResponder([
324
333
  { key: 'body', value: 'Body content' },
325
334
  { key: 'title', value: 'new value' },
326
335
  { key: 'clickUrl', value: 'http://www.example.com' },
327
336
  { key: 'image', value: 'http://www.image.com/picture.jpg' },
328
337
  ],url,null);
329
-
338
+
330
339
  const nativeAssetManager = makeManager();
331
340
  nativeAssetManager.loadAssets(AD_ID);
332
-
341
+
333
342
  expect(win.document.body.innerHTML).to.include(`<a href="http://www.example.com" target="_blank" class="pb-click">new value</a>`);
334
343
  expect(win.document.body.innerHTML).to.include(`<img class="pb-icon" src="http://www.image.com/picture.jpg" alt="icon" height="150" width="50">`);
335
344
  expect(win.document.body.innerHTML).to.include(`<p>Body content</p>`);
336
345
  });
337
-
346
+
338
347
  it("no placeholders found but requests all assets flag set - adTemplate - openRTB", () => {
339
348
  const template = `
340
349
  <div class="sponsored-post">
@@ -348,6 +357,7 @@ describe('nativeAssetManager', () => {
348
357
  <div class="attribution">
349
358
  <img class="pb-icon" src="##hb_native_asset_id_3##" alt="icon" height="150" width="50">
350
359
  </div>
360
+ <h2>##hb_native_asset_id_1##</h2>
351
361
  <p>##hb_native_asset_id_4##</p>
352
362
  </div>
353
363
  </div>
@@ -357,9 +367,9 @@ describe('nativeAssetManager', () => {
357
367
  adId: AD_ID,
358
368
  requestAllAssets: true,
359
369
  };
360
-
370
+
361
371
  win.document.body.innerHTML = "";
362
-
372
+
363
373
  win.addEventListener = createAllResponder(
364
374
  {
365
375
  assets: [
@@ -391,10 +401,10 @@ describe('nativeAssetManager', () => {
391
401
  template,
392
402
  "ortb"
393
403
  );
394
-
404
+
395
405
  const nativeAssetManager = makeManager();
396
406
  nativeAssetManager.loadAssets(AD_ID);
397
-
407
+
398
408
  expect(win.document.body.innerHTML).to.include(
399
409
  `<a href="http://www.example.com" target="_blank" class="pb-click">new value</a>`
400
410
  );
@@ -403,11 +413,14 @@ describe('nativeAssetManager', () => {
403
413
  );
404
414
  expect(win.document.body.innerHTML).to.include(`<p>Body content</p>`);
405
415
 
406
- // ##hb_native_asset_id_4## was not returned in the response, it should
416
+ // ##hb_native_asset_id_4## was not returned in the response, it should
407
417
  // be transformed into an empty string
408
418
  expect(win.document.body.innerHTML).to.not.include(`##hb_native_asset_id_4##`);
419
+
420
+ // test that we are replacing ALL asset occurrences
421
+ expect(([...win.document.body.innerHTML.match(/new value/g)] || []).length, "expected 2 occurrences of \"new value\"").to.equal(2);
409
422
  });
410
-
423
+
411
424
  it('no placeholders found but requests all assets flag set - adTemplate', () => {
412
425
  const template = '<div class=\"sponsored-post\">\r\n <div class=\"thumbnail\"><\/div>\r\n <div class=\"content\">\r\n <h1>\r\n <a href=\"##hb_native_linkurl##\" target=\"_blank\" class=\"pb-click\">##hb_native_title##<\/a>\r\n <\/h1>\r\n <p>##hb_native_body##<\/p>\r\n \t<div class=\"attribution\">\r\n \t<img class=\"pb-icon\" src=\"##hb_native_image##\" alt=\"icon\" height=\"150\" width=\"50\">\r\n \t\r\n \t<\/div>\r\n\t<\/div>\r\n<\/div>';
413
426
  win.pbNativeData = {
@@ -415,24 +428,24 @@ describe('nativeAssetManager', () => {
415
428
  adId : AD_ID,
416
429
  requestAllAssets : true
417
430
  };
418
-
431
+
419
432
  win.document.body.innerHTML = '';
420
-
433
+
421
434
  win.addEventListener = createAllResponder([
422
435
  { key: 'body', value: 'Body content' },
423
436
  { key: 'title', value: 'new value' },
424
437
  { key: 'clickUrl', value: 'http://www.example.com' },
425
438
  { key: 'image', value: 'http://www.image.com/picture.jpg' },
426
439
  ],null,template);
427
-
440
+
428
441
  const nativeAssetManager = makeManager();
429
442
  nativeAssetManager.loadAssets(AD_ID);
430
-
443
+
431
444
  expect(win.document.body.innerHTML).to.include(`<a href="http://www.example.com" target="_blank" class="pb-click">new value</a>`);
432
445
  expect(win.document.body.innerHTML).to.include(`<img class="pb-icon" src="http://www.image.com/picture.jpg" alt="icon" height="150" width="50">`);
433
446
  expect(win.document.body.innerHTML).to.include(`<p>Body content</p>`);
434
447
  });
435
-
448
+
436
449
  it('no placeholders found but assets defined in nativeTag - adTemplate', () => {
437
450
  const template = '<div class=\"sponsored-post\">\r\n <div class=\"thumbnail\"><\/div>\r\n <div class=\"content\">\r\n <h1>\r\n <a href=\"##hb_native_linkurl##\" target=\"_blank\" class=\"pb-click\">##hb_native_title##<\/a>\r\n <\/h1>\r\n <p>##hb_native_body##<\/p>\r\n \t<div class=\"attribution\">\r\n \t<img class=\"pb-icon\" src=\"##hb_native_image##\" alt=\"icon\" height=\"150\" width=\"50\">\r\n \t\r\n \t<\/div>\r\n\t<\/div>\r\n<\/div>';
438
451
  win.pbNativeData = {
@@ -440,54 +453,54 @@ describe('nativeAssetManager', () => {
440
453
  adId : AD_ID,
441
454
  assetsToReplace: ['image','hb_native_body','clickUrl','hb_native_title']
442
455
  };
443
-
456
+
444
457
  win.document.body.innerHTML = '';
445
-
458
+
446
459
  win.addEventListener = createAllResponder([
447
460
  { key: 'body', value: 'Body content' },
448
461
  { key: 'title', value: 'new value' },
449
462
  { key: 'clickUrl', value: 'http://www.example.com' },
450
463
  { key: 'image', value: 'http://www.image.com/picture.jpg' },
451
464
  ],null,template);
452
-
465
+
453
466
  const nativeAssetManager = makeManager();
454
467
  nativeAssetManager.loadAssets(AD_ID);
455
-
468
+
456
469
  expect(win.document.body.innerHTML).to.include(`<a href="http://www.example.com" target="_blank" class="pb-click">new value</a>`);
457
470
  expect(win.document.body.innerHTML).to.include(`<img class="pb-icon" src="http://www.image.com/picture.jpg" alt="icon" height="150" width="50">`);
458
471
  expect(win.document.body.innerHTML).to.include(`<p>Body content</p>`);
459
472
  });
460
-
473
+
461
474
  it('does not replace anything if no placeholders found', () => {
462
475
  const html = `
463
476
  <h1>Native Ad</h1>
464
477
  <p>Cool Description</p>
465
478
  <a href="http://www.example.com">Click</a>
466
479
  `;
467
-
480
+
468
481
  win.document.body.innerHTML = html;
469
482
  win.addEventListener = createResponder();
470
-
483
+
471
484
  const nativeAssetManager = makeManager();
472
485
  nativeAssetManager.loadAssets(AD_ID);
473
-
486
+
474
487
  expect(win.document.body.innerHTML).to.equal(html);
475
488
  });
476
-
489
+
477
490
  it('replace mobile native placeholder with their values', function() {
478
491
  win.document.body.innerHTML = `
479
492
  <h1>hb_native_cta</h1>
480
493
  <p>hb_native_body</p>
481
494
  <a href="hb_native_linkurl">Click Here</a>
482
495
  `;
483
-
496
+
484
497
  let cb = sinon.spy();
485
498
  let targetingData = {
486
499
  uuid: '123'
487
500
  }
488
-
501
+
489
502
  sinon.stub(utils, 'sendRequest').callsFake(function(arg1, cb) {
490
- let response = JSON.stringify({
503
+ let response = JSON.stringify({
491
504
  id: '6572251357847878203',
492
505
  impid: 'some-imp-id',
493
506
  price: 10,
@@ -498,21 +511,21 @@ describe('nativeAssetManager', () => {
498
511
  cid: '9325',
499
512
  crid: '97494204',
500
513
  cat: [ 'IAB3-1' ],
501
- ext: {
502
- appnexus: {
514
+ ext: {
515
+ appnexus: {
503
516
  brand_id: 555545,
504
517
  auction_id: 4550134868038456300,
505
518
  bidder_id: 2,
506
- bid_ad_type: 3
519
+ bid_ad_type: 3
507
520
  }
508
521
  }
509
522
  });
510
523
  cb(response);
511
524
  });
512
-
525
+
513
526
  const nativeAssetManager = makeManager();
514
527
  nativeAssetManager.loadMobileAssets(targetingData, cb);
515
-
528
+
516
529
  utils.sendRequest.restore();
517
530
 
518
531
  expect(win.document.body.innerHTML).to.include('<p>new value</p>');
@@ -526,23 +539,23 @@ describe('nativeAssetManager', () => {
526
539
  })
527
540
 
528
541
  describe('safe frame disabled', () => {
529
-
542
+
530
543
  beforeEach(() => {
531
544
  win.parent.frames = [win];
532
545
  win.parent.document = {
533
- getElementsByTagName: sinon.stub().returns([{
546
+ getElementsByTagName: sinon.stub().returns([{
534
547
  contentWindow: win,
535
548
  parentElement: {
536
549
  getBoundingClientRect: () => ({
537
550
  width: 600
538
551
  }),
539
552
  children: [{
540
- width: '1',
553
+ width: '1',
541
554
  height: '1'
542
555
  }]
543
556
  }
544
557
  }])
545
- }
558
+ }
546
559
  })
547
560
 
548
561
  it('should set the iframe to the width of the container', () => {
@@ -559,7 +572,7 @@ describe('nativeAssetManager', () => {
559
572
  adId : AD_ID,
560
573
  adTemplate : '<div class=\"sponsored-post\">\r\n <div class=\"thumbnail\"><\/div>\r\n <div class=\"content\">\r\n <h1>\r\n <a href=\"##hb_native_linkurl##\" target=\"_blank\" class=\"pb-click\">##hb_native_title##<\/a>\r\n <\/h1>\r\n <p>##hb_native_body##<\/p>\r\n \t<div class=\"attribution\">\r\n \t<img class=\"pb-icon\" src=\"##hb_native_image##\" alt=\"icon\" height=\"150\" width=\"50\">\r\n \t\r\n \t<\/div>\r\n\t<\/div>\r\n<\/div>'
561
574
  };
562
-
575
+
563
576
  win.document.body.innerHTML = html;
564
577
  win.addEventListener = createResponder([
565
578
  { key: 'body', value: 'Body content' },
@@ -567,14 +580,149 @@ describe('nativeAssetManager', () => {
567
580
  { key: 'clickUrl', value: 'http://www.example.com' },
568
581
  { key: 'image', value: 'http://www.image.com/picture.jpg' },
569
582
  ]);
570
-
583
+
571
584
  const nativeAssetManager = makeManager();
572
585
  nativeAssetManager.loadAssets(AD_ID);
573
-
586
+
574
587
  expect(win.document.body.innerHTML).to.include(`<a href="http://www.example.com" target="_blank" class="pb-click">new value</a>`);
575
588
  expect(win.document.body.innerHTML).to.include(`<img class="pb-icon" src="http://www.image.com/picture.jpg" alt="icon" height="150" width="50">`);
576
589
  expect(win.document.body.innerHTML).to.include(`<p>Body content</p>`);
577
590
  expect(win.document.body.style.width).to.equal('600px');
578
591
  });
579
592
  });
593
+
594
+ describe('loadAssets calls error callback', () => {
595
+ let recvMessages, reply;
596
+
597
+ function mockMessenger() {
598
+ return function (msg, cb) {
599
+ reply = cb;
600
+ recvMessages.push(msg);
601
+ };
602
+ }
603
+
604
+ beforeEach(() => {
605
+ recvMessages = [];
606
+ reply = null;
607
+ });
608
+
609
+
610
+ it('when there are no assets to load', () => {
611
+ win.pbNativeData = {adId: 123};
612
+ const mgr = makeManager(mockMessenger);
613
+ const cb = sinon.spy();
614
+ const errCb = sinon.spy();
615
+ mgr.loadAssets(123, cb, errCb);
616
+ expect(cb.called).to.be.false;
617
+ expect(errCb.called).to.be.true;
618
+ });
619
+
620
+ Object.entries({
621
+ 'all assets': {
622
+ adId: 123,
623
+ requestAllAssets: true
624
+ },
625
+ 'some assets': {
626
+ adId: 123,
627
+ }
628
+ }).forEach(([t, pbData]) => {
629
+ describe(t, () => {
630
+ let mgr;
631
+ beforeEach(() => {
632
+ win.pbNativeData = pbData;
633
+ win.document.body.innerHTML = '##hb_native_title##';
634
+ mgr = makeManager({}, mockMessenger);
635
+ });
636
+
637
+ it('on response "timeout"', () => {
638
+ const cb = sinon.spy();
639
+ const err = sinon.spy();
640
+ mgr.loadAssets(123, cb, err);
641
+ for (let i = 0; i < 12; i++) {
642
+ reply({data: 'invalid'});
643
+ }
644
+ expect(cb.called).to.be.false;
645
+ expect(err.called).to.be.true;
646
+ });
647
+
648
+ it('on rendering exceptions', () => {
649
+ const cb = sinon.spy();
650
+ const err = sinon.spy();
651
+ mgr.loadAssets(123, cb, err);
652
+ win.renderAd = () => {
653
+ throw new Error();
654
+ };
655
+ reply({
656
+ data: JSON.stringify({
657
+ message: 'assetResponse',
658
+ adId: 123,
659
+ rendererUrl: 'mock-render'
660
+ })
661
+ });
662
+ expect(cb.called).to.be.false;
663
+ expect(err.called).to.be.true;
664
+ });
665
+ });
666
+ });
667
+ });
668
+
669
+ describe('GAM macro %%CLICK_URL_UNESC%%', () => {
670
+ it("should remove %%CLICK_URL_UNESC%% if there's no variable set", () => {
671
+ const html = `<script>
672
+ let nativeTag = {};
673
+ nativeTag.adTemplate = "<div class=\"sponsored-post\">\r\n <div class=\"thumbnail\"><\/div>\r\n <div class=\"content\">\r\n <h1>\r\n <a href=\"%%CLICK_URL_UNESC%%##hb_native_linkurl##\" target=\"_blank\" class=\"pb-click\">##hb_native_title##<\/a>\r\n <\/h1>\r\n <p>##hb_native_body##<\/p>\r\n \t<div class=\"attribution\">\r\n \t<img class=\"pb-icon\" src=\"##hb_native_image##\" alt=\"icon\" height=\"150\" width=\"50\">\r\n \t\r\n \t<\/div>\r\n\t<\/div>\r\n<\/div>";
674
+ nativeTag.pubUrl = "https://www.url.com";
675
+ nativeTag.adId = "`+AD_ID+`";
676
+ nativeTag.requestAllAssets = true;
677
+ window.pbNativeTag.renderNativeAd(nativeTag);
678
+ </script>`;
679
+ win.pbNativeData = {
680
+ pubUrl : 'https://www.url.com',
681
+ adId : AD_ID,
682
+ adTemplate : '<div class=\"sponsored-post\">\r\n <div class=\"thumbnail\"><\/div>\r\n <div class=\"content\">\r\n <h1>\r\n <a href=\"%%CLICK_URL_UNESC%%##hb_native_linkurl##\" target=\"_blank\" class=\"pb-click\">##hb_native_title##<\/a>\r\n <\/h1>\r\n <p>##hb_native_body##<\/p>\r\n \t<div class=\"attribution\">\r\n \t<img class=\"pb-icon\" src=\"##hb_native_image##\" alt=\"icon\" height=\"150\" width=\"50\">\r\n \t\r\n \t<\/div>\r\n\t<\/div>\r\n<\/div>'
683
+ };
684
+
685
+ win.document.body.innerHTML = html;
686
+ win.addEventListener = createResponder([
687
+ { key: 'body', value: 'Body content' },
688
+ { key: 'title', value: 'new value' },
689
+ { key: 'clickUrl', value: 'http://www.example.com' },
690
+ { key: 'image', value: 'http://www.image.com/picture.jpg' },
691
+ ]);
692
+
693
+ const nativeAssetManager = makeManager();
694
+ nativeAssetManager.loadAssets(AD_ID);
695
+
696
+ expect(win.document.body.innerHTML).to.include(`<a href="http://www.example.com" target="_blank" class="pb-click">new value</a>`);
697
+ });
698
+
699
+ it("should substitute %%CLICK_URL_UNESC%% with clickUrlUnesc value", () => {
700
+ const html = `<script>
701
+ let nativeTag = {};
702
+ nativeTag.adTemplate = "<div class=\"sponsored-post\">\r\n <div class=\"thumbnail\"><\/div>\r\n <div class=\"content\">\r\n <h1>\r\n <a href=\"%%CLICK_URL_UNESC%%##hb_native_linkurl##\" target=\"_blank\" class=\"pb-click\">##hb_native_title##<\/a>\r\n <\/h1>\r\n <p>##hb_native_body##<\/p>\r\n \t<div class=\"attribution\">\r\n \t<img class=\"pb-icon\" src=\"##hb_native_image##\" alt=\"icon\" height=\"150\" width=\"50\">\r\n \t\r\n \t<\/div>\r\n\t<\/div>\r\n<\/div>";
703
+ nativeTag.pubUrl = "https://www.url.com";
704
+ nativeTag.adId = "`+AD_ID+`";
705
+ nativeTag.requestAllAssets = true;
706
+ window.pbNativeTag.renderNativeAd(nativeTag);
707
+ </script>`;
708
+ win.pbNativeData = {
709
+ pubUrl : 'https://www.url.com',
710
+ adId : AD_ID,
711
+ adTemplate : '<div class=\"sponsored-post\">\r\n <div class=\"thumbnail\"><\/div>\r\n <div class=\"content\">\r\n <h1>\r\n <a href=\"%%CLICK_URL_UNESC%%##hb_native_linkurl##\" target=\"_blank\" class=\"pb-click\">##hb_native_title##<\/a>\r\n <\/h1>\r\n <p>##hb_native_body##<\/p>\r\n \t<div class=\"attribution\">\r\n \t<img class=\"pb-icon\" src=\"##hb_native_image##\" alt=\"icon\" height=\"150\" width=\"50\">\r\n \t\r\n \t<\/div>\r\n\t<\/div>\r\n<\/div>',
712
+ };
713
+
714
+ win.document.body.innerHTML = html;
715
+ win.addEventListener = createResponder([
716
+ { key: 'body', value: 'Body content' },
717
+ { key: 'title', value: 'new value' },
718
+ { key: 'clickUrl', value: 'http://www.example.com' },
719
+ { key: 'image', value: 'http://www.image.com/picture.jpg' },
720
+ ], null, null, );
721
+
722
+ const nativeAssetManager = makeManager({ clickUrlUnesc: 'https://will.redirect/?to='});
723
+ nativeAssetManager.loadAssets(AD_ID);
724
+
725
+ expect(win.document.body.innerHTML).to.include(`<a href="https://will.redirect/?to=http://www.example.com" target="_blank" class="pb-click">new value</a>`);
726
+ });
727
+ });
580
728
  });