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