prebid-universal-creative 1.15.0 → 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.
@@ -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';
@@ -40,11 +41,16 @@ const mockDocument = {
40
41
  };
41
42
 
42
43
  // creates mock postmessage response from prebid's native.js:getAssetMessage
43
- function createResponder(assets,url,template) {
44
+ function createResponder(assets,url,template, clickUrlUnesc = '') {
44
45
  return function(type, listener) {
45
46
  if (type !== 'message') { return; }
46
47
 
47
- 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
+ };
48
54
  listener({ data: JSON.stringify(data), origin: ORIGIN});
49
55
  };
50
56
  }
@@ -86,8 +92,11 @@ function generateRenderer(assets) {
86
92
  describe('nativeAssetManager', () => {
87
93
  let win;
88
94
 
89
- function makeManager() {
90
- return newNativeAssetManager(win, ORIGIN);
95
+ function makeManager(args, mkMessenger = prebidMessenger) {
96
+ return newNativeAssetManager(win, {
97
+ pubUrl: ORIGIN,
98
+ ...args
99
+ }, mkMessenger);
91
100
  }
92
101
 
93
102
  beforeEach(() => {
@@ -112,10 +121,10 @@ describe('nativeAssetManager', () => {
112
121
  { key: 'body', value: 'new value' },
113
122
  { key: 'clickUrl', value: 'http://www.example.com' },
114
123
  ]);
115
-
124
+
116
125
  const nativeAssetManager = makeManager();
117
126
  nativeAssetManager.loadAssets(AD_ID);
118
-
127
+
119
128
  expect(win.document.body.innerHTML).to.include('<p>new value</p>');
120
129
  expect(win.document.body.innerHTML).to.include(`
121
130
  <a href="http://www.example.com">Click Here</a>
@@ -123,17 +132,17 @@ describe('nativeAssetManager', () => {
123
132
  // title was not a requested asset so this should stay as is
124
133
  expect(win.document.body.innerHTML).to.include('<h1>hb_native_title</h1>');
125
134
  });
126
-
135
+
127
136
  it('replaces all occurrences of the placeholder if it appears more than once', () => {
128
137
  win.document.body.innerHTML = `
129
138
  <a href="hb_native_linkurl:${AD_ID}">Click Here</a>
130
139
  <a href="hb_native_linkurl:${AD_ID}">Or Here</a>
131
140
  `;
132
141
  win.addEventListener = createResponder([{ key: 'clickUrl', value: 'http://www.example.com' }]);
133
-
142
+
134
143
  const nativeAssetManager = makeManager();
135
144
  nativeAssetManager.loadAssets(AD_ID);
136
-
145
+
137
146
  expect(win.document.body.innerHTML).to.include(`
138
147
  <a href="http://www.example.com">Click Here</a>
139
148
  `);
@@ -141,23 +150,22 @@ describe('nativeAssetManager', () => {
141
150
  <a href="http://www.example.com">Or Here</a>
142
151
  `);
143
152
  });
144
-
153
+
145
154
  it('attaches and removes message listeners', (done) => {
146
155
  win.document.body.innerHTML = `<h1>hb_native_title:${AD_ID}</h1>`;
147
156
  const responder = createResponder();
148
157
  win.addEventListener = function (evType, listener) {
149
158
  setTimeout(() => responder(evType, listener), 0);
150
159
  }
151
-
160
+
152
161
  const nativeAssetManager = makeManager();
153
162
  nativeAssetManager.loadAssets(AD_ID);
154
163
  setTimeout(() => {
155
- expect(win.parent.postMessage.callCount).to.equal(1);
156
164
  expect(win.removeEventListener.callCount).to.equal(1);
157
165
  done();
158
166
  }, 0);
159
167
  });
160
-
168
+
161
169
  it('replaces native placeholders with their asset values from adTemplate', () => {
162
170
  const html = `<script>
163
171
  let nativeTag = {};
@@ -172,7 +180,7 @@ describe('nativeAssetManager', () => {
172
180
  adId : AD_ID,
173
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>'
174
182
  };
175
-
183
+
176
184
  win.document.body.innerHTML = html;
177
185
  win.addEventListener = createResponder([
178
186
  { key: 'body', value: 'Body content' },
@@ -180,15 +188,15 @@ describe('nativeAssetManager', () => {
180
188
  { key: 'clickUrl', value: 'http://www.example.com' },
181
189
  { key: 'image', value: 'http://www.image.com/picture.jpg' },
182
190
  ]);
183
-
191
+
184
192
  const nativeAssetManager = makeManager();
185
193
  nativeAssetManager.loadAssets(AD_ID);
186
-
194
+
187
195
  expect(win.document.body.innerHTML).to.include(`<a href="http://www.example.com" target="_blank" class="pb-click">new value</a>`);
188
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">`);
189
197
  expect(win.document.body.innerHTML).to.include(`<p>Body content</p>`);
190
198
  });
191
-
199
+
192
200
  it('loads rendererUrl and passes assets to renderAd - writes response to innerHtml', () => {
193
201
  const html = `<script>
194
202
  let nativeTag = {};
@@ -203,25 +211,25 @@ describe('nativeAssetManager', () => {
203
211
  rendererUrl : 'https://www.renderer.com/render.js',
204
212
  requestAllAssets : true
205
213
  };
206
-
214
+
207
215
  win.document.body.innerHTML = html;
208
216
  win.renderAd = generateRenderer;
209
-
217
+
210
218
  win.addEventListener = createAllResponder([
211
219
  { key: 'body', value: 'Body content' },
212
220
  { key: 'title', value: 'new value' },
213
221
  { key: 'clickUrl', value: 'http://www.example.com' },
214
222
  { key: 'image', value: 'http://www.image.com/picture.jpg' },
215
223
  ],null,null);
216
-
224
+
217
225
  const nativeAssetManager = makeManager();
218
226
  nativeAssetManager.loadAssets(AD_ID);
219
-
227
+
220
228
  expect(win.document.body.innerHTML).to.include(`<a href="http://www.example.com" target="_blank" class="pb-click">new value</a>`);
221
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">`);
222
230
  expect(win.document.body.innerHTML).to.include(`<p>Body content</p>`);
223
231
  });
224
-
232
+
225
233
  it('adId does not match, so assets are not replaced', () => {
226
234
  const html = `<script>
227
235
  let nativeTag = {};
@@ -236,20 +244,20 @@ describe('nativeAssetManager', () => {
236
244
  rendererUrl : 'https://www.renderer.com/render.js',
237
245
  requestAllAssets : true
238
246
  };
239
-
247
+
240
248
  win.document.body.innerHTML = html;
241
249
  win.renderAd = generateRenderer;
242
-
250
+
243
251
  win.addEventListener = createAllResponder([
244
252
  { key: 'body', value: 'Body content' },
245
253
  { key: 'title', value: 'new value' },
246
254
  { key: 'clickUrl', value: 'http://www.example.com' },
247
255
  { key: 'image', value: 'http://www.image.com/picture.jpg' },
248
256
  ],null,null);
249
-
257
+
250
258
  const nativeAssetManager = makeManager();
251
259
  nativeAssetManager.loadAssets(AD_ID);
252
-
260
+
253
261
  expect(win.document.body.innerHTML).to.equal(`<script>
254
262
  let nativeTag = {};
255
263
  nativeTag.pubUrl = "https://www.url.com";
@@ -258,7 +266,7 @@ describe('nativeAssetManager', () => {
258
266
  window.pbNativeTag.renderNativeAd(nativeTag);
259
267
  </script>`);
260
268
  });
261
-
269
+
262
270
  it('adId does not match on first response, so assets are not replaced until match on second response', () => {
263
271
  const html = `<script>
264
272
  let nativeTag = {};
@@ -273,20 +281,20 @@ describe('nativeAssetManager', () => {
273
281
  rendererUrl : 'https://www.renderer.com/render.js',
274
282
  requestAllAssets : true
275
283
  };
276
-
284
+
277
285
  win.document.body.innerHTML = html;
278
286
  win.renderAd = generateRenderer;
279
-
287
+
280
288
  win.addEventListener = createAllResponder([
281
289
  { key: 'body', value: 'Body No Replace' },
282
290
  { key: 'title', value: 'new value no replace' },
283
291
  { key: 'clickUrl', value: 'http://www.example.com/noreplace' },
284
292
  { key: 'image', value: 'http://www.image.com/picture.jpg?noreplace=true' },
285
293
  ],null,null);
286
-
294
+
287
295
  const nativeAssetManager = makeManager();
288
296
  nativeAssetManager.loadAssets(AD_ID2);
289
-
297
+
290
298
  expect(win.document.body.innerHTML).to.equal(`<script>
291
299
  let nativeTag = {};
292
300
  nativeTag.pubUrl = "https://www.url.com";
@@ -294,21 +302,21 @@ describe('nativeAssetManager', () => {
294
302
  nativeTag.requestAllAssets = true;
295
303
  window.pbNativeTag.renderNativeAd(nativeTag);
296
304
  </script>`);
297
-
305
+
298
306
  win.addEventListener = createAltAllResponder([
299
307
  { key: 'body', value: 'Body content' },
300
308
  { key: 'title', value: 'new value' },
301
309
  { key: 'clickUrl', value: 'http://www.example.com' },
302
310
  { key: 'image', value: 'http://www.image.com/picture.jpg' },
303
311
  ],null,null);
304
-
312
+
305
313
  nativeAssetManager.loadAssets(AD_ID2);
306
-
314
+
307
315
  expect(win.document.body.innerHTML).to.include(`<a href="http://www.example.com" target="_blank" class="pb-click">new value</a>`);
308
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">`);
309
317
  expect(win.document.body.innerHTML).to.include(`<p>Body content</p>`);
310
318
  });
311
-
319
+
312
320
  it('no placeholders found but requests all assets flag set - rendererUrl', () => {
313
321
  const url = 'https://www.renderer.com/render.js';
314
322
  win.pbNativeData = {
@@ -317,25 +325,25 @@ describe('nativeAssetManager', () => {
317
325
  rendererUrl : 'https://www.renderer.com/render.js',
318
326
  requestAllAssets : true
319
327
  };
320
-
328
+
321
329
  win.document.body.innerHTML = '';
322
330
  win.renderAd = generateRenderer;
323
-
331
+
324
332
  win.addEventListener = createAllResponder([
325
333
  { key: 'body', value: 'Body content' },
326
334
  { key: 'title', value: 'new value' },
327
335
  { key: 'clickUrl', value: 'http://www.example.com' },
328
336
  { key: 'image', value: 'http://www.image.com/picture.jpg' },
329
337
  ],url,null);
330
-
338
+
331
339
  const nativeAssetManager = makeManager();
332
340
  nativeAssetManager.loadAssets(AD_ID);
333
-
341
+
334
342
  expect(win.document.body.innerHTML).to.include(`<a href="http://www.example.com" target="_blank" class="pb-click">new value</a>`);
335
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">`);
336
344
  expect(win.document.body.innerHTML).to.include(`<p>Body content</p>`);
337
345
  });
338
-
346
+
339
347
  it("no placeholders found but requests all assets flag set - adTemplate - openRTB", () => {
340
348
  const template = `
341
349
  <div class="sponsored-post">
@@ -349,6 +357,7 @@ describe('nativeAssetManager', () => {
349
357
  <div class="attribution">
350
358
  <img class="pb-icon" src="##hb_native_asset_id_3##" alt="icon" height="150" width="50">
351
359
  </div>
360
+ <h2>##hb_native_asset_id_1##</h2>
352
361
  <p>##hb_native_asset_id_4##</p>
353
362
  </div>
354
363
  </div>
@@ -358,9 +367,9 @@ describe('nativeAssetManager', () => {
358
367
  adId: AD_ID,
359
368
  requestAllAssets: true,
360
369
  };
361
-
370
+
362
371
  win.document.body.innerHTML = "";
363
-
372
+
364
373
  win.addEventListener = createAllResponder(
365
374
  {
366
375
  assets: [
@@ -392,10 +401,10 @@ describe('nativeAssetManager', () => {
392
401
  template,
393
402
  "ortb"
394
403
  );
395
-
404
+
396
405
  const nativeAssetManager = makeManager();
397
406
  nativeAssetManager.loadAssets(AD_ID);
398
-
407
+
399
408
  expect(win.document.body.innerHTML).to.include(
400
409
  `<a href="http://www.example.com" target="_blank" class="pb-click">new value</a>`
401
410
  );
@@ -404,11 +413,14 @@ describe('nativeAssetManager', () => {
404
413
  );
405
414
  expect(win.document.body.innerHTML).to.include(`<p>Body content</p>`);
406
415
 
407
- // ##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
408
417
  // be transformed into an empty string
409
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);
410
422
  });
411
-
423
+
412
424
  it('no placeholders found but requests all assets flag set - adTemplate', () => {
413
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>';
414
426
  win.pbNativeData = {
@@ -416,24 +428,24 @@ describe('nativeAssetManager', () => {
416
428
  adId : AD_ID,
417
429
  requestAllAssets : true
418
430
  };
419
-
431
+
420
432
  win.document.body.innerHTML = '';
421
-
433
+
422
434
  win.addEventListener = createAllResponder([
423
435
  { key: 'body', value: 'Body content' },
424
436
  { key: 'title', value: 'new value' },
425
437
  { key: 'clickUrl', value: 'http://www.example.com' },
426
438
  { key: 'image', value: 'http://www.image.com/picture.jpg' },
427
439
  ],null,template);
428
-
440
+
429
441
  const nativeAssetManager = makeManager();
430
442
  nativeAssetManager.loadAssets(AD_ID);
431
-
443
+
432
444
  expect(win.document.body.innerHTML).to.include(`<a href="http://www.example.com" target="_blank" class="pb-click">new value</a>`);
433
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">`);
434
446
  expect(win.document.body.innerHTML).to.include(`<p>Body content</p>`);
435
447
  });
436
-
448
+
437
449
  it('no placeholders found but assets defined in nativeTag - adTemplate', () => {
438
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>';
439
451
  win.pbNativeData = {
@@ -441,54 +453,54 @@ describe('nativeAssetManager', () => {
441
453
  adId : AD_ID,
442
454
  assetsToReplace: ['image','hb_native_body','clickUrl','hb_native_title']
443
455
  };
444
-
456
+
445
457
  win.document.body.innerHTML = '';
446
-
458
+
447
459
  win.addEventListener = createAllResponder([
448
460
  { key: 'body', value: 'Body content' },
449
461
  { key: 'title', value: 'new value' },
450
462
  { key: 'clickUrl', value: 'http://www.example.com' },
451
463
  { key: 'image', value: 'http://www.image.com/picture.jpg' },
452
464
  ],null,template);
453
-
465
+
454
466
  const nativeAssetManager = makeManager();
455
467
  nativeAssetManager.loadAssets(AD_ID);
456
-
468
+
457
469
  expect(win.document.body.innerHTML).to.include(`<a href="http://www.example.com" target="_blank" class="pb-click">new value</a>`);
458
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">`);
459
471
  expect(win.document.body.innerHTML).to.include(`<p>Body content</p>`);
460
472
  });
461
-
473
+
462
474
  it('does not replace anything if no placeholders found', () => {
463
475
  const html = `
464
476
  <h1>Native Ad</h1>
465
477
  <p>Cool Description</p>
466
478
  <a href="http://www.example.com">Click</a>
467
479
  `;
468
-
480
+
469
481
  win.document.body.innerHTML = html;
470
482
  win.addEventListener = createResponder();
471
-
483
+
472
484
  const nativeAssetManager = makeManager();
473
485
  nativeAssetManager.loadAssets(AD_ID);
474
-
486
+
475
487
  expect(win.document.body.innerHTML).to.equal(html);
476
488
  });
477
-
489
+
478
490
  it('replace mobile native placeholder with their values', function() {
479
491
  win.document.body.innerHTML = `
480
492
  <h1>hb_native_cta</h1>
481
493
  <p>hb_native_body</p>
482
494
  <a href="hb_native_linkurl">Click Here</a>
483
495
  `;
484
-
496
+
485
497
  let cb = sinon.spy();
486
498
  let targetingData = {
487
499
  uuid: '123'
488
500
  }
489
-
501
+
490
502
  sinon.stub(utils, 'sendRequest').callsFake(function(arg1, cb) {
491
- let response = JSON.stringify({
503
+ let response = JSON.stringify({
492
504
  id: '6572251357847878203',
493
505
  impid: 'some-imp-id',
494
506
  price: 10,
@@ -499,21 +511,21 @@ describe('nativeAssetManager', () => {
499
511
  cid: '9325',
500
512
  crid: '97494204',
501
513
  cat: [ 'IAB3-1' ],
502
- ext: {
503
- appnexus: {
514
+ ext: {
515
+ appnexus: {
504
516
  brand_id: 555545,
505
517
  auction_id: 4550134868038456300,
506
518
  bidder_id: 2,
507
- bid_ad_type: 3
519
+ bid_ad_type: 3
508
520
  }
509
521
  }
510
522
  });
511
523
  cb(response);
512
524
  });
513
-
525
+
514
526
  const nativeAssetManager = makeManager();
515
527
  nativeAssetManager.loadMobileAssets(targetingData, cb);
516
-
528
+
517
529
  utils.sendRequest.restore();
518
530
 
519
531
  expect(win.document.body.innerHTML).to.include('<p>new value</p>');
@@ -527,23 +539,23 @@ describe('nativeAssetManager', () => {
527
539
  })
528
540
 
529
541
  describe('safe frame disabled', () => {
530
-
542
+
531
543
  beforeEach(() => {
532
544
  win.parent.frames = [win];
533
545
  win.parent.document = {
534
- getElementsByTagName: sinon.stub().returns([{
546
+ getElementsByTagName: sinon.stub().returns([{
535
547
  contentWindow: win,
536
548
  parentElement: {
537
549
  getBoundingClientRect: () => ({
538
550
  width: 600
539
551
  }),
540
552
  children: [{
541
- width: '1',
553
+ width: '1',
542
554
  height: '1'
543
555
  }]
544
556
  }
545
557
  }])
546
- }
558
+ }
547
559
  })
548
560
 
549
561
  it('should set the iframe to the width of the container', () => {
@@ -560,7 +572,7 @@ describe('nativeAssetManager', () => {
560
572
  adId : AD_ID,
561
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>'
562
574
  };
563
-
575
+
564
576
  win.document.body.innerHTML = html;
565
577
  win.addEventListener = createResponder([
566
578
  { key: 'body', value: 'Body content' },
@@ -568,14 +580,149 @@ describe('nativeAssetManager', () => {
568
580
  { key: 'clickUrl', value: 'http://www.example.com' },
569
581
  { key: 'image', value: 'http://www.image.com/picture.jpg' },
570
582
  ]);
571
-
583
+
572
584
  const nativeAssetManager = makeManager();
573
585
  nativeAssetManager.loadAssets(AD_ID);
574
-
586
+
575
587
  expect(win.document.body.innerHTML).to.include(`<a href="http://www.example.com" target="_blank" class="pb-click">new value</a>`);
576
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">`);
577
589
  expect(win.document.body.innerHTML).to.include(`<p>Body content</p>`);
578
590
  expect(win.document.body.style.width).to.equal('600px');
579
591
  });
580
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
+ });
581
728
  });