prebid.js 9.46.0 → 9.48.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 (325) hide show
  1. package/.github/codeql/queries/jsonRequestContentType.ql +18 -0
  2. package/AGENTS.md +42 -0
  3. package/CLAUDE.md +1 -0
  4. package/babelConfig.js +1 -1
  5. package/dist/33acrossAnalyticsAdapter.js +1 -1
  6. package/dist/33acrossBidAdapter.js +1 -1
  7. package/dist/33acrossIdSystem.js +1 -1
  8. package/dist/BTBidAdapter.js +1 -1
  9. package/dist/adagioAnalyticsAdapter.js +1 -1
  10. package/dist/adagioBidAdapter.js +1 -1
  11. package/dist/adagioUtils.js +1 -1
  12. package/dist/addefendBidAdapter.js +1 -1
  13. package/dist/adgenerationBidAdapter.js +1 -1
  14. package/dist/adlooxRtdProvider.js +1 -1
  15. package/dist/adqueryBidAdapter.js +1 -1
  16. package/dist/adrelevantisBidAdapter.js +1 -1
  17. package/dist/adstirBidAdapter.js +1 -1
  18. package/dist/adtrgtmeBidAdapter.js +1 -1
  19. package/dist/advangUtils.js +1 -1
  20. package/dist/adverxoBidAdapter.js +1 -1
  21. package/dist/adxcgAnalyticsAdapter.js +1 -1
  22. package/dist/adxcgBidAdapter.js +1 -1
  23. package/dist/adyoulikeBidAdapter.js +1 -1
  24. package/dist/agmaAnalyticsAdapter.js +1 -1
  25. package/dist/ajaBidAdapter.js +1 -1
  26. package/dist/amxBidAdapter.js +1 -1
  27. package/dist/amxIdSystem.js +1 -1
  28. package/dist/aniviewBidAdapter.js +1 -1
  29. package/dist/appierAnalyticsAdapter.js +1 -1
  30. package/dist/appnexusBidAdapter.js +1 -1
  31. package/dist/asoBidAdapter.js +1 -1
  32. package/dist/axonixBidAdapter.js +1 -1
  33. package/dist/beopBidAdapter.js +1 -1
  34. package/dist/bidglassBidAdapter.js +1 -1
  35. package/dist/big-richmediaBidAdapter.js +1 -1
  36. package/dist/bitmediaBidAdapter.js +1 -1
  37. package/dist/blueBidAdapter.js +1 -1
  38. package/dist/blueUtils.js +1 -0
  39. package/dist/bmsBidAdapter.js +1 -1
  40. package/dist/bridBidAdapter.js +1 -1
  41. package/dist/bridgeuppBidAdapter.js +1 -1
  42. package/dist/bridgewellBidAdapter.js +1 -1
  43. package/dist/brightMountainMediaBidAdapter.js +1 -1
  44. package/dist/browsiUtils.js +1 -1
  45. package/dist/carodaBidAdapter.js +1 -1
  46. package/dist/chtnwBidAdapter.js +1 -1
  47. package/dist/chunk-core.js +1 -1
  48. package/dist/concertBidAdapter.js +1 -1
  49. package/dist/connectadBidAdapter.js +1 -1
  50. package/dist/consumableBidAdapter.js +1 -1
  51. package/dist/contxtfulBidAdapter.js +1 -1
  52. package/dist/conversantAnalyticsAdapter.js +1 -1
  53. package/dist/conversantBidAdapter.js +1 -1
  54. package/dist/craftBidAdapter.js +1 -1
  55. package/dist/criteoBidAdapter.js +1 -1
  56. package/dist/cwireBidAdapter.js +1 -1
  57. package/dist/czechAdIdSystem.js +1 -1
  58. package/dist/dailymotionBidAdapter.js +1 -1
  59. package/dist/debugging-standalone.js +1 -1
  60. package/dist/dependencies.json +16 -2
  61. package/dist/dspxBidAdapter.js +1 -1
  62. package/dist/dxkultureBidAdapter.js +1 -1
  63. package/dist/dynamicAdBoostRtdProvider.js +1 -1
  64. package/dist/eplanningBidAdapter.js +1 -1
  65. package/dist/eskimiBidAdapter.js +1 -1
  66. package/dist/euidIdSystem.js +1 -1
  67. package/dist/exadsBidAdapter.js +1 -1
  68. package/dist/excoBidAdapter.js +1 -1
  69. package/dist/feedadBidAdapter.js +1 -1
  70. package/dist/finativeBidAdapter.js +1 -1
  71. package/dist/freewheel-sspBidAdapter.js +1 -1
  72. package/dist/gmosspBidAdapter.js +1 -1
  73. package/dist/gptUtils.js +1 -1
  74. package/dist/greenbidsAnalyticsAdapter.js +1 -1
  75. package/dist/greenbidsBidAdapter.js +1 -1
  76. package/dist/greenbidsRtdProvider.js +1 -1
  77. package/dist/gridBidAdapter.js +1 -1
  78. package/dist/gumgumBidAdapter.js +1 -1
  79. package/dist/h12mediaBidAdapter.js +1 -1
  80. package/dist/hypelabBidAdapter.js +1 -1
  81. package/dist/id5AnalyticsAdapter.js +1 -1
  82. package/dist/id5IdSystem.js +1 -1
  83. package/dist/imdsBidAdapter.js +1 -1
  84. package/dist/improvedigitalBidAdapter.js +1 -1
  85. package/dist/inmobiBidAdapter.js +1 -1
  86. package/dist/insticatorBidAdapter.js +1 -1
  87. package/dist/intentIqAnalyticsAdapter.js +1 -1
  88. package/dist/ixBidAdapter.js +1 -1
  89. package/dist/jixieBidAdapter.js +1 -1
  90. package/dist/justpremiumBidAdapter.js +1 -1
  91. package/dist/kargoBidAdapter.js +1 -1
  92. package/dist/kimberliteBidAdapter.js +1 -1
  93. package/dist/konduitAnalyticsAdapter.js +1 -1
  94. package/dist/kueezBidAdapter.js +1 -1
  95. package/dist/lassoBidAdapter.js +1 -1
  96. package/dist/lifestreetBidAdapter.js +1 -1
  97. package/dist/liveIntentId.js +1 -1
  98. package/dist/logicadBidAdapter.js +1 -1
  99. package/dist/loglyliftBidAdapter.js +1 -1
  100. package/dist/luceadBidAdapter.js +1 -1
  101. package/dist/luponmediaBidAdapter.js +1 -1
  102. package/dist/mabidderBidAdapter.js +1 -1
  103. package/dist/madsenseBidAdapter.js +1 -1
  104. package/dist/magniteAnalyticsAdapter.js +1 -1
  105. package/dist/malltvAnalyticsAdapter.js +1 -1
  106. package/dist/marsmediaBidAdapter.js +1 -1
  107. package/dist/mediafuseBidAdapter.js +1 -1
  108. package/dist/medianetBidAdapter.js +1 -1
  109. package/dist/medianetUtils.js +1 -1
  110. package/dist/mediasquareBidAdapter.js +1 -1
  111. package/dist/mgidBidAdapter.js +1 -1
  112. package/dist/missenaBidAdapter.js +1 -1
  113. package/dist/mobilefuseBidAdapter.js +1 -1
  114. package/dist/nativeryBidAdapter.js +1 -0
  115. package/dist/nextMillenniumBidAdapter.js +1 -1
  116. package/dist/nexx360Utils.js +1 -1
  117. package/dist/nobidAnalyticsAdapter.js +1 -1
  118. package/dist/nobidBidAdapter.js +1 -1
  119. package/dist/nodalsAiRtdProvider.js +1 -1
  120. package/dist/not-for-prod/prebid.js +187 -184
  121. package/dist/oguryBidAdapter.js +1 -1
  122. package/dist/onetagBidAdapter.js +1 -1
  123. package/dist/ooloAnalyticsAdapter.js +1 -1
  124. package/dist/openxBidAdapter.js +1 -1
  125. package/dist/optidigitalBidAdapter.js +1 -1
  126. package/dist/orbidderBidAdapter.js +1 -1
  127. package/dist/outbrainBidAdapter.js +1 -1
  128. package/dist/pinkLionBidAdapter.js +1 -0
  129. package/dist/pixfutureBidAdapter.js +1 -1
  130. package/dist/prebidServerBidAdapter.js +1 -1
  131. package/dist/priceFloors.js +1 -1
  132. package/dist/publinkIdSystem.js +1 -1
  133. package/dist/pubmaticAnalyticsAdapter.js +1 -1
  134. package/dist/pubmaticBidAdapter.js +1 -1
  135. package/dist/pubmaticRtdProvider.js +1 -1
  136. package/dist/pubwiseAnalyticsAdapter.js +1 -1
  137. package/dist/pubxaiAnalyticsAdapter.js +1 -1
  138. package/dist/pubxaiRtdProvider.js +1 -1
  139. package/dist/pxyzBidAdapter.js +1 -1
  140. package/dist/quantcastBidAdapter.js +1 -1
  141. package/dist/readpeakBidAdapter.js +1 -1
  142. package/dist/relaidoBidAdapter.js +1 -1
  143. package/dist/retailspotBidAdapter.js +1 -1
  144. package/dist/rhythmoneBidAdapter.js +1 -1
  145. package/dist/riseUtils.js +1 -1
  146. package/dist/rtbhouseBidAdapter.js +1 -1
  147. package/dist/rubiconBidAdapter.js +1 -1
  148. package/dist/seedingAllianceBidAdapter.js +1 -1
  149. package/dist/seedtagBidAdapter.js +1 -1
  150. package/dist/sharethroughAnalyticsAdapter.js +1 -1
  151. package/dist/sharethroughBidAdapter.js +1 -1
  152. package/dist/showheroes-bsBidAdapter.js +1 -1
  153. package/dist/smaatoBidAdapter.js +1 -1
  154. package/dist/smartadserverBidAdapter.js +1 -1
  155. package/dist/smartxBidAdapter.js +1 -1
  156. package/dist/smilewantedBidAdapter.js +1 -1
  157. package/dist/snigelBidAdapter.js +1 -1
  158. package/dist/sonobiBidAdapter.js +1 -1
  159. package/dist/sovrnBidAdapter.js +1 -1
  160. package/dist/sparteoBidAdapter.js +1 -1
  161. package/dist/sspBCBidAdapter.js +1 -1
  162. package/dist/stroeerCoreBidAdapter.js +1 -1
  163. package/dist/stvBidAdapter.js +1 -1
  164. package/dist/sublimeBidAdapter.js +1 -1
  165. package/dist/taboolaBidAdapter.js +1 -1
  166. package/dist/tappxBidAdapter.js +1 -1
  167. package/dist/targetVideoBidAdapter.js +1 -1
  168. package/dist/teadsBidAdapter.js +1 -1
  169. package/dist/terceptAnalyticsAdapter.js +1 -1
  170. package/dist/themoneytizerBidAdapter.js +1 -1
  171. package/dist/trionBidAdapter.js +1 -1
  172. package/dist/tripleliftBidAdapter.js +1 -1
  173. package/dist/ttdBidAdapter.js +1 -1
  174. package/dist/ucfunnelAnalyticsAdapter.js +1 -1
  175. package/dist/uid2IdSystem.js +1 -1
  176. package/dist/underdogmediaBidAdapter.js +1 -1
  177. package/dist/undertoneBidAdapter.js +1 -1
  178. package/dist/unifiedIdSystem.js +1 -1
  179. package/dist/unrulyBidAdapter.js +1 -1
  180. package/dist/userId.js +1 -1
  181. package/dist/vidazooUtils.js +1 -1
  182. package/dist/videobyteBidAdapter.js +1 -1
  183. package/dist/visxBidAdapter.js +1 -1
  184. package/dist/vuukleBidAdapter.js +1 -1
  185. package/dist/weboramaRtdProvider.js +1 -1
  186. package/dist/widespaceBidAdapter.js +1 -1
  187. package/dist/winrBidAdapter.js +1 -1
  188. package/dist/xeUtils.js +1 -1
  189. package/dist/yahooAdsBidAdapter.js +1 -1
  190. package/dist/yandexBidAdapter.js +1 -1
  191. package/dist/yieldmoBidAdapter.js +1 -1
  192. package/dist/yieldoneAnalyticsAdapter.js +1 -1
  193. package/eslint.config.js +1 -3
  194. package/gulpHelpers.js +3 -6
  195. package/gulpfile.js +25 -24
  196. package/karma.conf.maker.js +1 -3
  197. package/libraries/advangUtils/index.js +3 -4
  198. package/libraries/blueUtils/bidderUtils.js +113 -0
  199. package/libraries/browsiUtils/browsiUtils.js +1 -2
  200. package/libraries/gptUtils/gptUtils.js +1 -2
  201. package/libraries/liveIntentId/shared.js +4 -0
  202. package/libraries/xeUtils/bidderUtils.js +3 -4
  203. package/modules/adagioBidAdapter.js +1 -2
  204. package/modules/addefendBidAdapter.md +1 -1
  205. package/modules/adtrgtmeBidAdapter.js +6 -8
  206. package/modules/aduptechBidAdapter.md +1 -1
  207. package/modules/adverxoBidAdapter.js +3 -3
  208. package/modules/blueBidAdapter.js +24 -104
  209. package/modules/bmsBidAdapter.js +25 -105
  210. package/modules/concertBidAdapter.md +1 -1
  211. package/modules/contxtfulBidAdapter.js +56 -10
  212. package/modules/conversantBidAdapter.js +0 -58
  213. package/modules/cwireBidAdapter.js +8 -0
  214. package/modules/czechAdIdSystem.js +13 -3
  215. package/modules/dynamicAdBoostRtdProvider.js +16 -33
  216. package/modules/dynamicAdBoostRtdProvider.md +1 -6
  217. package/modules/ixBidAdapter.js +2 -3
  218. package/modules/luponmediaBidAdapter.js +117 -522
  219. package/modules/luponmediaBidAdapter.md +2 -3
  220. package/modules/mediasquareBidAdapter.js +14 -20
  221. package/modules/microadBidAdapter.js +0 -1
  222. package/modules/nativeryBidAdapter.js +135 -0
  223. package/modules/nativeryBidAdapter.md +95 -0
  224. package/modules/nativoBidAdapter.js +3 -3
  225. package/modules/onetagBidAdapter.js +0 -1
  226. package/modules/pinkLionBidAdapter.js +17 -0
  227. package/modules/pinkLionBidAdapter.md +79 -0
  228. package/modules/prebidServerBidAdapter/ortbConverter.js +1 -1
  229. package/modules/priceFloors.js +2 -2
  230. package/modules/pubmaticBidAdapter.js +4 -1
  231. package/modules/qortexRtdProvider.md +1 -1
  232. package/modules/reconciliationRtdProvider.md +4 -4
  233. package/modules/rtbhouseBidAdapter.js +4 -83
  234. package/modules/rubiconBidAdapter.js +1 -1
  235. package/modules/sspBCBidAdapter.js +1 -1
  236. package/modules/stroeerCoreBidAdapter.js +3 -3
  237. package/modules/stvBidAdapter.js +19 -14
  238. package/modules/topicsFpdModule.md +1 -1
  239. package/modules/unifiedIdSystem.js +8 -1
  240. package/modules/userId/eids.js +15 -0
  241. package/modules/videoModule/index.js +0 -1
  242. package/modules/videoModule/videoImpressionVerifier.js +0 -1
  243. package/modules/yieldlabBidAdapter.js +1 -2
  244. package/modules/yieldmoBidAdapter.js +1 -2
  245. package/package.json +13 -20
  246. package/src/Renderer.js +1 -2
  247. package/src/adapterManager.js +14 -4
  248. package/src/auction.js +2 -3
  249. package/src/config.js +1 -2
  250. package/src/cpmBucketManager.js +1 -2
  251. package/src/secureCreatives.js +2 -3
  252. package/src/targeting.js +1 -2
  253. package/test/fake-server/README.md +3 -3
  254. package/test/helpers/index_adapter_utils.js +2 -2
  255. package/test/helpers/testing-utils.js +1 -1
  256. package/test/spec/auctionmanager_spec.js +2 -3
  257. package/test/spec/fpd/enrichment_spec.js +1 -1
  258. package/test/spec/libraries/greedy/greedyPromise_spec.js +2 -2
  259. package/test/spec/modules/adfBidAdapter_spec.js +1 -1
  260. package/test/spec/modules/adnuntiusBidAdapter_spec.js +25 -9
  261. package/test/spec/modules/adtrgtmeBidAdapter_spec.js +2 -4
  262. package/test/spec/modules/adverxoBidAdapter_spec.js +25 -1
  263. package/test/spec/modules/afpBidAdapter_spec.js +0 -1
  264. package/test/spec/modules/bliinkBidAdapter_spec.js +15 -7
  265. package/test/spec/modules/contxtfulBidAdapter_spec.js +606 -82
  266. package/test/spec/modules/conversantBidAdapter_spec.js +1 -139
  267. package/test/spec/modules/cwireBidAdapter_spec.js +2 -2
  268. package/test/spec/modules/czechAdIdSystem_spec.js +4 -4
  269. package/test/spec/modules/displayioBidAdapter_spec.js +1 -1
  270. package/test/spec/modules/dynamicAdBoostRtdProvider_spec.js +0 -42
  271. package/test/spec/modules/enrichmentLiftMeasurement_spec.js +8 -8
  272. package/test/spec/modules/hypelabBidAdapter_spec.js +17 -11
  273. package/test/spec/modules/iasRtdProvider_spec.js +2 -2
  274. package/test/spec/modules/id5IdSystem_spec.js +1 -1
  275. package/test/spec/modules/idxIdSystem_spec.js +1 -2
  276. package/test/spec/modules/intentIqAnalyticsAdapter_spec.js +25 -25
  277. package/test/spec/modules/intentIqIdSystem_spec.js +32 -32
  278. package/test/spec/modules/kargoBidAdapter_spec.js +11 -5
  279. package/test/spec/modules/liveIntentIdSystem_spec.js +14 -0
  280. package/test/spec/modules/lmpIdSystem_spec.js +1 -2
  281. package/test/spec/modules/lockrAIMIdSystem_spec.js +2 -2
  282. package/test/spec/modules/luceadBidAdapter_spec.js +1 -1
  283. package/test/spec/modules/luponmediaBidAdapter_spec.js +186 -324
  284. package/test/spec/modules/mediaeyesBidAdapter_spec.js +1 -1
  285. package/test/spec/modules/mediakeysBidAdapter_spec.js +1 -2
  286. package/test/spec/modules/mediasquareBidAdapter_spec.js +13 -2
  287. package/test/spec/modules/missenaBidAdapter_spec.js +1 -1
  288. package/test/spec/modules/nativeryBidAdapter_spec.js +195 -0
  289. package/test/spec/modules/nexx360BidAdapter_spec.js +6 -6
  290. package/test/spec/modules/oguryBidAdapter_spec.js +2 -2
  291. package/test/spec/modules/omsBidAdapter_spec.js +1 -1
  292. package/test/spec/modules/onetagBidAdapter_spec.js +1 -2
  293. package/test/spec/modules/onomagicBidAdapter_spec.js +2 -2
  294. package/test/spec/modules/overtoneRtdProvider_spec.mjs +1 -1
  295. package/test/spec/modules/permutiveIdentityManagerIdSystem_spec.js +17 -14
  296. package/test/spec/modules/pinkLionBidAdapter_spec.js +480 -0
  297. package/test/spec/modules/prebidServerBidAdapter_spec.js +2 -2
  298. package/test/spec/modules/previousAuctionInfo_spec.js +2 -2
  299. package/test/spec/modules/pubmaticAnalyticsAdapter_spec.js +1 -1
  300. package/test/spec/modules/pubmaticBidAdapter_spec.js +19 -1
  301. package/test/spec/modules/pubmaticRtdProvider_spec.js +16 -17
  302. package/test/spec/modules/pubwiseAnalyticsAdapter_spec.js +2 -2
  303. package/test/spec/modules/rtbhouseBidAdapter_spec.js +0 -182
  304. package/test/spec/modules/rubiconBidAdapter_spec.js +3 -4
  305. package/test/spec/modules/sizeMappingV2_spec.js +1 -1
  306. package/test/spec/modules/sizeMapping_spec.js +2 -3
  307. package/test/spec/modules/stroeerCoreBidAdapter_spec.js +36 -26
  308. package/test/spec/modules/stvBidAdapter_spec.js +108 -40
  309. package/test/spec/modules/topLevelPaapi_spec.js +1 -1
  310. package/test/spec/modules/tpmnBidAdapter_spec.js +1 -1
  311. package/test/spec/modules/ttdBidAdapter_spec.js +1 -1
  312. package/test/spec/modules/unifiedIdSystem_spec.js +20 -0
  313. package/test/spec/modules/userId_spec.js +1 -1
  314. package/test/spec/modules/vibrantmediaBidAdapter_spec.js +1 -1
  315. package/test/spec/modules/videoModule/submodules/videojsVideoProvider_spec.js +1 -1
  316. package/test/spec/modules/yieldmoBidAdapter_spec.js +2 -2
  317. package/test/spec/modules/zeotapIdPlusIdSystem_spec.js +1 -2
  318. package/test/spec/unit/core/adapterManager_spec.js +29 -17
  319. package/test/spec/unit/core/targeting_spec.js +1 -1
  320. package/test/spec/unit/pbjs_api_spec.js +4 -5
  321. package/test/spec/utils_spec.js +20 -12
  322. package/test/test_deps.js +1 -1
  323. package/nightwatch.browserstack.json +0 -46
  324. package/nightwatch.conf.js +0 -36
  325. package/nightwatch.json +0 -40
@@ -1,4 +1,4 @@
1
- import { spec } from 'modules/contxtfulBidAdapter.js';
1
+ import { spec, safeStringify } from 'modules/contxtfulBidAdapter.js';
2
2
  import { newBidder } from 'src/adapters/bidderFactory.js';
3
3
  import { config } from 'src/config.js';
4
4
  import * as ajax from 'src/ajax.js';
@@ -19,6 +19,514 @@ describe('contxtful bid adapter', function () {
19
19
  sandbox.restore();
20
20
  });
21
21
 
22
+ describe('SafeStringify function', function () {
23
+ it('should stringify normal objects successfully', function () {
24
+ const normalObject = { name: 'test', value: 123, active: true };
25
+ const result = safeStringify(normalObject);
26
+ expect(result).to.equal('{"name":"test","value":123,"active":true}');
27
+ });
28
+
29
+ it('should handle arrays correctly', function () {
30
+ const array = [1, 2, 'three', { nested: true }];
31
+ const result = safeStringify(array);
32
+ expect(result).to.equal('[1,2,"three",{"nested":true}]');
33
+ });
34
+
35
+ it('should handle circular references', function () {
36
+ const objA = { name: 'A' };
37
+ const objB = { name: 'B', ref: objA };
38
+ objA.ref = objB; // Create circular reference
39
+
40
+ const result = safeStringify(objA);
41
+ expect(result).to.be.a('string');
42
+ expect(result).to.include('[Circular]');
43
+ expect(result).to.include('"name":"A"');
44
+ });
45
+
46
+ it('should handle functions by omitting them (standard JSON.stringify behavior)', function () {
47
+ const objWithFunction = {
48
+ name: 'test',
49
+ method: function () { return 'hello'; },
50
+ arrow: () => 'world'
51
+ };
52
+
53
+ const result = safeStringify(objWithFunction);
54
+ expect(result).to.equal('{"name":"test"}');
55
+ expect(result).to.not.include('[Function]');
56
+ });
57
+
58
+ it('should handle undefined values by omitting them (standard JSON.stringify behavior)', function () {
59
+ const objWithUndefined = {
60
+ name: 'test',
61
+ undefinedValue: undefined,
62
+ nullValue: null
63
+ };
64
+
65
+ const result = safeStringify(objWithUndefined);
66
+ expect(result).to.equal('{"name":"test","nullValue":null}');
67
+ expect(result).to.not.include('[Undefined]');
68
+ });
69
+
70
+ it('should handle mixed complex objects', function () {
71
+ const complexObj = {
72
+ string: 'test',
73
+ number: 42,
74
+ boolean: true,
75
+ nullVal: null,
76
+ undefinedVal: undefined,
77
+ func: function () { return 'test'; },
78
+ nested: {
79
+ array: [1, 2, function () { }],
80
+ date: new Date('2023-01-01')
81
+ }
82
+ };
83
+
84
+ const result = safeStringify(complexObj);
85
+ expect(result).to.be.a('string');
86
+ expect(result).to.include('"string":"test"');
87
+ expect(result).to.include('"number":42');
88
+ // Functions and undefined values are omitted by standard JSON.stringify
89
+ expect(result).to.not.include('[Function]');
90
+ expect(result).to.not.include('[Undefined]');
91
+ });
92
+
93
+ it('should handle nested circular references', function () {
94
+ const parent = { name: 'parent', children: [] };
95
+ const child1 = { name: 'child1', parent: parent };
96
+ const child2 = { name: 'child2', parent: parent };
97
+ parent.children.push(child1, child2);
98
+
99
+ const result = safeStringify(parent);
100
+ expect(result).to.be.a('string');
101
+ expect(result).to.include('[Circular]');
102
+ expect(result).to.include('"name":"parent"');
103
+ });
104
+
105
+ it('should handle empty objects and arrays', function () {
106
+ expect(safeStringify({})).to.equal('{}');
107
+ expect(safeStringify([])).to.equal('[]');
108
+ });
109
+
110
+ it('should handle primitive values', function () {
111
+ expect(safeStringify('string')).to.equal('"string"');
112
+ expect(safeStringify(123)).to.equal('123');
113
+ expect(safeStringify(true)).to.equal('true');
114
+ expect(safeStringify(null)).to.equal('null');
115
+ });
116
+
117
+ it('should handle Date objects', function () {
118
+ const date = new Date('2023-01-01T00:00:00.000Z');
119
+ const result = safeStringify(date);
120
+ expect(result).to.include('2023-01-01');
121
+ });
122
+
123
+ it('should handle bigint values by converting them to strings', function () {
124
+ const objWithBigInt = {
125
+ name: 'test',
126
+ bigNumber: BigInt('12345678901234567890'),
127
+ regularNumber: 123
128
+ };
129
+
130
+ const result = safeStringify(objWithBigInt);
131
+ expect(result).to.include('"bigNumber":"12345678901234567890"');
132
+ expect(result).to.include('"name":"test"');
133
+ expect(result).to.include('"regularNumber":123');
134
+ });
135
+
136
+ it('should handle objects with toJSON methods', function () {
137
+ const objWithToJSON = {
138
+ name: 'test',
139
+ toJSON: function () {
140
+ return { serialized: true };
141
+ }
142
+ };
143
+
144
+ const result = safeStringify(objWithToJSON);
145
+ expect(result).to.equal('{"serialized":true}');
146
+ });
147
+
148
+ it('should fall back to safeJSONEncode for completely unstringifiable objects', function () {
149
+ // Mock an object that breaks JSON.stringify even with replacer
150
+ const problematicObj = {};
151
+ Object.defineProperty(problematicObj, 'problematic', {
152
+ get: function () {
153
+ throw new Error('Cannot access this property');
154
+ },
155
+ enumerable: true
156
+ });
157
+
158
+ const result = safeStringify(problematicObj);
159
+ // Should not throw and should return a string
160
+ expect(result).to.be.a('string');
161
+ });
162
+
163
+ it('should handle browser Window objects safely', function () {
164
+ const objWithWindow = {
165
+ name: 'test',
166
+ windowRef: window
167
+ };
168
+
169
+ const result = safeStringify(objWithWindow);
170
+ expect(result).to.include('[Browser Object]');
171
+ expect(result).to.include('"name":"test"');
172
+ });
173
+
174
+ it('should handle objects with inaccessible properties', function () {
175
+ const problematicObj = {
176
+ name: 'test',
177
+ safeData: 'value',
178
+ normalProperty: 'normal'
179
+ };
180
+
181
+ // Instead of testing property access errors (which can break entire stringify),
182
+ // let's test that the function handles objects that contain browser objects
183
+ // which should be converted to [Inaccessible Object] or [Browser Object]
184
+ if (typeof window !== 'undefined') {
185
+ problematicObj.browserRef = window;
186
+ }
187
+
188
+ const result = safeStringify(problematicObj);
189
+ expect(result).to.be.a('string');
190
+ expect(result).to.include('"name":"test"');
191
+ expect(result).to.include('"safeData":"value"');
192
+ expect(result).to.include('"normalProperty":"normal"');
193
+
194
+ if (typeof window !== 'undefined') {
195
+ expect(result).to.include('[Browser Object]');
196
+ }
197
+ });
198
+
199
+ it('should handle mixed problematic objects', function () {
200
+ const mixedObj = {
201
+ normal: 'value',
202
+ windowRef: window,
203
+ circular: null
204
+ };
205
+ mixedObj.circular = mixedObj; // Create circular reference
206
+
207
+ const result = safeStringify(mixedObj);
208
+ expect(result).to.include('[Browser Object]');
209
+ expect(result).to.include('[Circular]');
210
+ expect(result).to.include('"normal":"value"');
211
+ });
212
+
213
+ it('should handle IMA3 video renderer objects safely', function () {
214
+ // Simulate the IMA3 video renderer object with simpler structure
215
+ const ima3RendererObj = {
216
+ url: "https://imasdk.googleapis.com/js/sdkloader/ima3.js",
217
+ renderNow: false,
218
+ cmd: [null],
219
+ someData: "test"
220
+ };
221
+
222
+ // Add a simple browser object reference that should be detected
223
+ if (typeof window !== 'undefined') {
224
+ ima3RendererObj.windowRef = window;
225
+ }
226
+
227
+ const result = safeStringify(ima3RendererObj);
228
+ expect(result).to.be.a('string');
229
+ expect(result).to.include('"url":"https://imasdk.googleapis.com/js/sdkloader/ima3.js"');
230
+ expect(result).to.include('"renderNow":false');
231
+ expect(result).to.include('"someData":"test"');
232
+ if (typeof window !== 'undefined') {
233
+ expect(result).to.include('[Browser Object]'); // for window reference
234
+ }
235
+ });
236
+
237
+ it('should handle complex nested objects with mixed browser elements', function () {
238
+ const complexBidData = {
239
+ bidId: 'test-bid-123',
240
+ adUnitCode: 'div-ad-unit',
241
+ cpm: 1.25,
242
+ currency: 'USD',
243
+ renderer: {
244
+ url: "https://imasdk.googleapis.com/js/sdkloader/ima3.js",
245
+ renderNow: false,
246
+ cmd: [null]
247
+ },
248
+ sizes: [[300, 250], [728, 90]]
249
+ };
250
+
251
+ // Add browser objects that should be detected by current implementation
252
+ if (typeof window !== 'undefined') {
253
+ complexBidData.windowContext = window;
254
+ }
255
+ if (typeof document !== 'undefined') {
256
+ complexBidData.documentRef = document;
257
+ }
258
+
259
+ const result = safeStringify(complexBidData);
260
+ expect(result).to.be.a('string');
261
+ expect(result).to.include('"bidId":"test-bid-123"');
262
+ expect(result).to.include('"cpm":1.25');
263
+ if (typeof window !== 'undefined' || typeof document !== 'undefined') {
264
+ expect(result).to.include('[Browser Object]');
265
+ }
266
+ });
267
+
268
+ it('should handle additional browser objects safely', function () {
269
+ const objWithBrowserObjects = {
270
+ name: 'test'
271
+ };
272
+
273
+ // Only test browser objects that are detected by current implementation
274
+ if (typeof window !== 'undefined') {
275
+ objWithBrowserObjects.windowRef = window;
276
+ }
277
+ if (typeof document !== 'undefined') {
278
+ objWithBrowserObjects.documentRef = document;
279
+ }
280
+
281
+ const result = safeStringify(objWithBrowserObjects);
282
+ expect(result).to.be.a('string');
283
+ expect(result).to.include('"name":"test"');
284
+
285
+ // Current implementation only detects Window, Document, HTMLElement, Node
286
+ // It doesn't detect navigator, location, etc. as browser objects
287
+ if (typeof window !== 'undefined' || typeof document !== 'undefined') {
288
+ expect(result).to.include('[Browser Object]');
289
+ }
290
+ });
291
+
292
+ it('should handle event objects and DOM-related objects', function () {
293
+ const objWithDOMObjects = {
294
+ bidId: 'test-123',
295
+ data: 'normal-data'
296
+ };
297
+
298
+ // Add DOM element if available in test environment
299
+ if (typeof document !== 'undefined') {
300
+ const div = document.createElement('div');
301
+ objWithDOMObjects.element = div;
302
+ }
303
+
304
+ // Simulate an event object
305
+ if (typeof Event !== 'undefined') {
306
+ try {
307
+ objWithDOMObjects.event = new Event('click');
308
+ } catch (e) {
309
+ // Some test environments might not support Event constructor
310
+ objWithDOMObjects.event = { type: 'click', target: null };
311
+ }
312
+ }
313
+
314
+ const result = safeStringify(objWithDOMObjects);
315
+ expect(result).to.be.a('string');
316
+ expect(result).to.include('"bidId":"test-123"');
317
+ expect(result).to.include('"data":"normal-data"');
318
+ });
319
+
320
+ it('should handle storage and web API objects safely', function () {
321
+ const objWithWebAPIs = {
322
+ name: 'test-data',
323
+ normalArray: [1, 2, 3]
324
+ };
325
+
326
+ // Add storage references if available
327
+ if (typeof globalThis.localStorage !== 'undefined') {
328
+ objWithWebAPIs.storage = globalThis.localStorage;
329
+ }
330
+
331
+ // Add Blob if available
332
+ if (typeof Blob !== 'undefined') {
333
+ try {
334
+ objWithWebAPIs.blob = new Blob(['test'], { type: 'text/plain' });
335
+ } catch (e) {
336
+ // Fallback if Blob not available in test environment
337
+ }
338
+ }
339
+
340
+ const result = safeStringify(objWithWebAPIs);
341
+ expect(result).to.be.a('string');
342
+ expect(result).to.include('"name":"test-data"');
343
+ expect(result).to.include('"normalArray":[1,2,3]');
344
+ // Should handle browser objects without throwing
345
+ expect(result).to.not.throw;
346
+ });
347
+
348
+ it('should detect browser objects using parent hierarchies and duck typing', function () {
349
+ const testObj = {
350
+ normalData: 'safe-value',
351
+ number: 42
352
+ };
353
+
354
+ // Add various types of browser objects that should be caught by parent classes
355
+ if (typeof document !== 'undefined') {
356
+ testObj.element = document.createElement('div'); // HTMLElement -> EventTarget
357
+ testObj.textNode = document.createTextNode('test'); // Text -> Node
358
+ }
359
+
360
+ // Add objects that should be caught by duck typing (constructor name patterns)
361
+ const mockObjects = [];
362
+
363
+ // Mock HTMLCanvasElement (constructor name contains 'HTML' and 'Canvas')
364
+ function HTMLCanvasElement() {}
365
+ const mockCanvas = Object.create(HTMLCanvasElement.prototype);
366
+ Object.defineProperty(mockCanvas, 'constructor', { value: HTMLCanvasElement });
367
+ testObj.mockCanvas = mockCanvas;
368
+
369
+ // Mock CSSStyleDeclaration (constructor name contains 'CSS')
370
+ function CSSStyleDeclaration() {}
371
+ const mockStyle = Object.create(CSSStyleDeclaration.prototype);
372
+ Object.defineProperty(mockStyle, 'constructor', { value: CSSStyleDeclaration });
373
+ testObj.mockStyle = mockStyle;
374
+
375
+ const result = safeStringify(testObj);
376
+ expect(result).to.be.a('string');
377
+ expect(result).to.include('"normalData":"safe-value"');
378
+ expect(result).to.include('"number":42');
379
+ expect(result).to.include('[Browser Object]');
380
+
381
+ // Should not contain the actual browser object data
382
+ expect(result).to.not.include('HTMLCanvasElement');
383
+ expect(result).to.not.include('CSSStyleDeclaration');
384
+ });
385
+
386
+ it('should detect objects with browser-like properties using duck typing', function () {
387
+ const testObj = {
388
+ safeData: 'value'
389
+ };
390
+
391
+ // Add actual browser objects that the current implementation can detect
392
+ if (typeof document !== 'undefined') {
393
+ const div = document.createElement('div');
394
+ testObj.element = div; // HTMLElement should be detected
395
+ }
396
+
397
+ if (typeof window !== 'undefined') {
398
+ testObj.windowRef = window; // Window should be detected
399
+ }
400
+
401
+ const result = safeStringify(testObj);
402
+ expect(result).to.be.a('string');
403
+ expect(result).to.include('"safeData":"value"');
404
+
405
+ // Only expect [Browser Object] if we actually added detectable browser objects
406
+ if (typeof document !== 'undefined' || typeof window !== 'undefined') {
407
+ expect(result).to.include('[Browser Object]');
408
+ }
409
+ });
410
+
411
+ it('should exclude specified keys when keysToExclude parameter is provided', function () {
412
+ const testObj = {
413
+ bidId: 'test-123',
414
+ cpm: 1.25,
415
+ renderer: {
416
+ url: 'https://example.com/renderer.js',
417
+ handlers: { onLoad: function() {} }
418
+ },
419
+ ad: '<div>Ad content</div>',
420
+ meta: {
421
+ advertiserDomains: ['example.com']
422
+ }
423
+ };
424
+
425
+ const result = safeStringify(testObj, ['renderer']);
426
+ expect(result).to.be.a('string');
427
+ expect(result).to.include('"bidId":"test-123"');
428
+ expect(result).to.include('"cpm":1.25');
429
+ expect(result).to.include('"ad":"<div>Ad content</div>"');
430
+ expect(result).to.include('[Excluded]'); // renderer should be excluded
431
+ expect(result).to.not.include('https://example.com/renderer.js');
432
+ });
433
+
434
+ it('should exclude multiple keys when multiple keys are specified', function () {
435
+ const testObj = {
436
+ bidId: 'test-456',
437
+ renderer: { url: 'renderer.js' },
438
+ ad: '<script>alert("ad")</script>',
439
+ privateData: 'sensitive',
440
+ normalData: 'safe'
441
+ };
442
+
443
+ const result = safeStringify(testObj, ['renderer', 'privateData']);
444
+ expect(result).to.be.a('string');
445
+ expect(result).to.include('"bidId":"test-456"');
446
+ expect(result).to.include('"normalData":"safe"');
447
+ expect(result).to.include('[Excluded]'); // Both excluded keys should show this
448
+ expect(result).to.not.include('renderer.js');
449
+ expect(result).to.not.include('sensitive');
450
+ // ad should still be included since it's not in exclude list
451
+ expect(result).to.include('"ad":"<script>alert(\\"ad\\")</script>"');
452
+ });
453
+
454
+ it('should exclude keys at any nesting level', function () {
455
+ const testObj = {
456
+ bid: {
457
+ id: 'test-789',
458
+ renderer: {
459
+ url: 'nested-renderer.js',
460
+ config: { timeout: 5000 }
461
+ },
462
+ meta: {
463
+ renderer: 'should also be excluded'
464
+ }
465
+ },
466
+ topLevel: 'value'
467
+ };
468
+
469
+ const result = safeStringify(testObj, ['renderer']);
470
+ expect(result).to.be.a('string');
471
+ expect(result).to.include('"id":"test-789"');
472
+ expect(result).to.include('"topLevel":"value"');
473
+ expect(result).to.include('[Excluded]'); // Both renderer keys should be excluded
474
+ expect(result).to.not.include('nested-renderer.js');
475
+ expect(result).to.not.include('should also be excluded');
476
+ });
477
+
478
+ it('should work correctly when keysToExclude is empty array', function () {
479
+ const testObj = {
480
+ bidId: 'test-empty',
481
+ renderer: { url: 'renderer.js' },
482
+ normalData: 'value'
483
+ };
484
+
485
+ const result = safeStringify(testObj, []);
486
+ expect(result).to.be.a('string');
487
+ expect(result).to.include('"bidId":"test-empty"');
488
+ expect(result).to.include('"normalData":"value"');
489
+ expect(result).to.include('renderer.js'); // Should not be excluded
490
+ expect(result).to.not.include('[Excluded]');
491
+ });
492
+
493
+ it('should work correctly when keysToExclude parameter is not provided', function () {
494
+ const testObj = {
495
+ bidId: 'test-no-param',
496
+ renderer: { url: 'renderer.js' },
497
+ normalData: 'value'
498
+ };
499
+
500
+ const result = safeStringify(testObj); // No second parameter
501
+ expect(result).to.be.a('string');
502
+ expect(result).to.include('"bidId":"test-no-param"');
503
+ expect(result).to.include('"normalData":"value"');
504
+ expect(result).to.include('renderer.js'); // Should not be excluded
505
+ expect(result).to.not.include('[Excluded]');
506
+ });
507
+
508
+ it('should combine key exclusion with browser object detection', function () {
509
+ const testObj = {
510
+ bidId: 'test-combined',
511
+ renderer: {
512
+ url: 'renderer.js',
513
+ windowRef: window,
514
+ handlers: {}
515
+ },
516
+ windowRef: window,
517
+ normalData: 'safe'
518
+ };
519
+
520
+ const result = safeStringify(testObj, ['renderer']);
521
+ expect(result).to.be.a('string');
522
+ expect(result).to.include('"bidId":"test-combined"');
523
+ expect(result).to.include('"normalData":"safe"');
524
+ expect(result).to.include('[Excluded]'); // renderer key excluded
525
+ expect(result).to.include('[Browser Object]'); // top-level windowRef detected as browser object
526
+ expect(result).to.not.include('renderer.js');
527
+ });
528
+ });
529
+
22
530
  describe('is a functions', function () {
23
531
  it('exists and is a function', function () {
24
532
  expect(adapter.callBids).to.exist.and.to.be.a('function');
@@ -32,44 +540,44 @@ describe('contxtful bid adapter', function () {
32
540
  });
33
541
 
34
542
  let bidRequests =
35
- [
36
- {
37
- bidder: 'contxtful',
38
- bidId: 'bId1',
39
- custom_param_1: 'value_1',
40
- transactionId: 'tId1',
41
- params: {
42
- bcat: ['cat1', 'cat2'],
43
- badv: ['adv1', 'adv2'],
44
- },
45
- mediaTypes: {
46
- banner: {
47
- sizes: [
48
- [300, 250],
49
- [300, 600]
50
- ]
543
+ [
544
+ {
545
+ bidder: 'contxtful',
546
+ bidId: 'bId1',
547
+ custom_param_1: 'value_1',
548
+ transactionId: 'tId1',
549
+ params: {
550
+ bcat: ['cat1', 'cat2'],
551
+ badv: ['adv1', 'adv2'],
51
552
  },
52
- },
53
- ortb2Imp: {
54
- ext: {
55
- tid: 't-id-test-1',
56
- gpid: 'gpid-id-unitest-1'
553
+ mediaTypes: {
554
+ banner: {
555
+ sizes: [
556
+ [300, 250],
557
+ [300, 600]
558
+ ]
559
+ },
57
560
  },
58
- },
59
- schain: {
60
- ver: '1.0',
61
- complete: 1,
62
- nodes: [
63
- {
64
- asi: 'schain-seller-1.com',
65
- sid: '00001',
66
- hp: 1,
561
+ ortb2Imp: {
562
+ ext: {
563
+ tid: 't-id-test-1',
564
+ gpid: 'gpid-id-unitest-1'
67
565
  },
68
- ],
69
- },
70
- getFloor: () => ({ currency: 'CAD', floor: 10 }),
71
- }
72
- ];
566
+ },
567
+ schain: {
568
+ ver: '1.0',
569
+ complete: 1,
570
+ nodes: [
571
+ {
572
+ asi: 'schain-seller-1.com',
573
+ sid: '00001',
574
+ hp: 1,
575
+ },
576
+ ],
577
+ },
578
+ getFloor: () => ({ currency: 'CAD', floor: 10 }),
579
+ }
580
+ ];
73
581
 
74
582
  let expectedReceptivityData = {
75
583
  rx: RX_FROM_API,
@@ -121,7 +629,7 @@ describe('contxtful bid adapter', function () {
121
629
  uspConsent: '12345'
122
630
  };
123
631
 
124
- describe('valid configuration', function() {
632
+ describe('valid configuration', function () {
125
633
  const theories = [
126
634
  [
127
635
  null,
@@ -175,7 +683,7 @@ describe('contxtful bid adapter', function () {
175
683
 
176
684
  it('uses a valid configuration and returns the right url', () => {
177
685
  config.setConfig({
178
- contxtful: {customer: CUSTOMER, version: VERSION}
686
+ contxtful: { customer: CUSTOMER, version: VERSION }
179
687
  });
180
688
  const bidRequest = spec.buildRequests(bidRequests);
181
689
  expect(bidRequest.url).to.eq('https://' + BIDDER_ENDPOINT + `/${VERSION}/prebid/${CUSTOMER}/bid`)
@@ -183,7 +691,7 @@ describe('contxtful bid adapter', function () {
183
691
 
184
692
  it('will take specific ortb2 configuration parameters and returns it in ortb2 object', () => {
185
693
  config.setConfig({
186
- contxtful: {customer: CUSTOMER, version: VERSION},
694
+ contxtful: { customer: CUSTOMER, version: VERSION },
187
695
  });
188
696
  const bidRequest = spec.buildRequests(bidRequests, bidderRequest);
189
697
  expect(bidRequest.data.ortb2.property_1).to.equal('string_val_1');
@@ -192,7 +700,7 @@ describe('contxtful bid adapter', function () {
192
700
 
193
701
  describe('valid bid request', function () {
194
702
  config.setConfig({
195
- contxtful: {customer: CUSTOMER, version: VERSION},
703
+ contxtful: { customer: CUSTOMER, version: VERSION },
196
704
  });
197
705
  const bidRequest = spec.buildRequests(bidRequests, bidderRequest);
198
706
 
@@ -239,7 +747,7 @@ describe('contxtful bid adapter', function () {
239
747
  });
240
748
 
241
749
  it('will contains the receptivity value within the ortb2.user.data with contxtful name', () => {
242
- let obtained_receptivity_data = bidRequest.data.ortb2.user.data.filter(function(userData) {
750
+ let obtained_receptivity_data = bidRequest.data.ortb2.user.data.filter(function (userData) {
243
751
  return userData.name == 'contxtful';
244
752
  });
245
753
  expect(obtained_receptivity_data.length).to.equal(1);
@@ -256,40 +764,40 @@ describe('contxtful bid adapter', function () {
256
764
 
257
765
  describe('valid bid request with no floor module', () => {
258
766
  let noFloorsBidRequests =
259
- [
260
- {
261
- bidder: 'contxtful',
262
- bidId: 'bId1',
263
- transactionId: 'tId1',
264
- mediaTypes: {
265
- banner: {
266
- sizes: [
267
- [300, 250],
268
- [300, 600]
269
- ]
767
+ [
768
+ {
769
+ bidder: 'contxtful',
770
+ bidId: 'bId1',
771
+ transactionId: 'tId1',
772
+ mediaTypes: {
773
+ banner: {
774
+ sizes: [
775
+ [300, 250],
776
+ [300, 600]
777
+ ]
778
+ },
270
779
  },
271
780
  },
272
- },
273
- {
274
- bidder: 'contxtful',
275
- bidId: 'bId2',
276
- transactionId: 'tId2',
277
- mediaTypes: {
278
- banner: {
279
- sizes: [
280
- [300, 250],
281
- [300, 600]
282
- ]
781
+ {
782
+ bidder: 'contxtful',
783
+ bidId: 'bId2',
784
+ transactionId: 'tId2',
785
+ mediaTypes: {
786
+ banner: {
787
+ sizes: [
788
+ [300, 250],
789
+ [300, 600]
790
+ ]
791
+ },
283
792
  },
793
+ params: {
794
+ bidfloor: 54
795
+ }
284
796
  },
285
- params: {
286
- bidfloor: 54
287
- }
288
- },
289
- ];
797
+ ];
290
798
 
291
799
  config.setConfig({
292
- contxtful: {customer: CUSTOMER, version: VERSION},
800
+ contxtful: { customer: CUSTOMER, version: VERSION },
293
801
  });
294
802
 
295
803
  const bidRequest = spec.buildRequests(noFloorsBidRequests, bidderRequest);
@@ -326,7 +834,7 @@ describe('contxtful bid adapter', function () {
326
834
  }
327
835
  ];
328
836
  config.setConfig({
329
- contxtful: {customer: CUSTOMER, version: VERSION},
837
+ contxtful: { customer: CUSTOMER, version: VERSION },
330
838
  });
331
839
 
332
840
  const bidRequest = spec.buildRequests(bidRequests, bidderRequest);
@@ -403,24 +911,24 @@ describe('contxtful bid adapter', function () {
403
911
  describe('onTimeout callback', () => {
404
912
  it('will always call server with sendBeacon available', () => {
405
913
  config.setConfig({
406
- contxtful: {customer: CUSTOMER, version: VERSION},
914
+ contxtful: { customer: CUSTOMER, version: VERSION },
407
915
  });
408
916
 
409
917
  const beaconStub = sandbox.stub(ajax, 'sendBeacon').returns(true);
410
918
  const ajaxStub = sandbox.stub(ajax, 'ajax');
411
- expect(spec.onTimeout({'customData': 'customvalue'})).to.not.throw;
919
+ expect(spec.onTimeout({ 'customData': 'customvalue' })).to.not.throw;
412
920
  expect(beaconStub.called).to.be.true;
413
921
  expect(ajaxStub.called).to.be.false;
414
922
  });
415
923
 
416
924
  it('will always call server with sendBeacon not available', () => {
417
925
  config.setConfig({
418
- contxtful: {customer: CUSTOMER, version: VERSION},
926
+ contxtful: { customer: CUSTOMER, version: VERSION },
419
927
  });
420
928
 
421
929
  const ajaxStub = sandbox.stub(ajax, 'ajax');
422
930
  const beaconStub = sandbox.stub(ajax, 'sendBeacon').returns(false);
423
- expect(spec.onTimeout({'customData': 'customvalue'})).to.not.throw;
931
+ expect(spec.onTimeout({ 'customData': 'customvalue' })).to.not.throw;
424
932
  expect(beaconStub.called).to.be.true;
425
933
  expect(beaconStub.returned(false)).to.be.true;
426
934
  expect(ajaxStub.calledOnce).to.be.true;
@@ -430,12 +938,12 @@ describe('contxtful bid adapter', function () {
430
938
  describe('on onBidderError callback', () => {
431
939
  it('will always call server', () => {
432
940
  config.setConfig({
433
- contxtful: {customer: CUSTOMER, version: VERSION},
941
+ contxtful: { customer: CUSTOMER, version: VERSION },
434
942
  });
435
943
 
436
944
  const ajaxStub = sandbox.stub(ajax, 'ajax');
437
945
  const beaconStub = sandbox.stub(ajax, 'sendBeacon').returns(false);
438
- spec.onBidderError({'customData': 'customvalue'});
946
+ spec.onBidderError({ 'customData': 'customvalue' });
439
947
  expect(ajaxStub.calledOnce).to.be.true;
440
948
  expect(beaconStub.returned(false)).to.be.true;
441
949
  });
@@ -444,25 +952,41 @@ describe('contxtful bid adapter', function () {
444
952
  describe('on onBidWon callback', () => {
445
953
  it('will always call server', () => {
446
954
  config.setConfig({
447
- contxtful: {customer: CUSTOMER, version: VERSION},
955
+ contxtful: { customer: CUSTOMER, version: VERSION },
448
956
  });
449
957
 
450
958
  const ajaxStub = sandbox.stub(ajax, 'ajax');
451
959
  const beaconStub = sandbox.stub(ajax, 'sendBeacon').returns(false);
452
- spec.onBidWon({'customData': 'customvalue'});
960
+ spec.onBidWon({ 'customData': 'customvalue' });
453
961
  expect(ajaxStub.calledOnce).to.be.true;
454
962
  expect(beaconStub.returned(false)).to.be.true;
455
963
  });
964
+
965
+ it('will call the server even if payload contains circular reference', () => {
966
+ config.setConfig({
967
+ contxtful: { customer: CUSTOMER, version: VERSION },
968
+ });
969
+
970
+ const ajaxStub = sandbox.stub(ajax, 'ajax');
971
+ const beaconStub = sandbox.stub(ajax, 'sendBeacon').returns(false);
972
+ const payload = {
973
+ adata: "hello"
974
+ };
975
+ payload.ref = payload
976
+ spec.onBidWon(payload);
977
+ expect(ajaxStub.calledOnce).to.be.true;
978
+ expect(beaconStub.returned(false)).to.be.true;
979
+ })
456
980
  });
457
981
 
458
982
  describe('on onBidBillable callback', () => {
459
983
  it('will always call server when sampling rate is configured to be 1.0', () => {
460
984
  config.setConfig({
461
- contxtful: {customer: CUSTOMER, version: VERSION, sampling: {onBidBillable: 1.0}},
985
+ contxtful: { customer: CUSTOMER, version: VERSION, sampling: { onBidBillable: 1.0 } },
462
986
  });
463
987
  const ajaxStub = sandbox.stub(ajax, 'ajax');
464
988
  const beaconStub = sandbox.stub(ajax, 'sendBeacon').returns(false);
465
- spec.onBidBillable({'customData': 'customvalue'});
989
+ spec.onBidBillable({ 'customData': 'customvalue' });
466
990
  expect(ajaxStub.calledOnce).to.be.true;
467
991
  expect(beaconStub.returned(false)).to.be.true;
468
992
  });
@@ -471,11 +995,11 @@ describe('contxtful bid adapter', function () {
471
995
  describe('on onAdRenderSucceeded callback', () => {
472
996
  it('will always call server when sampling rate is configured to be 1.0', () => {
473
997
  config.setConfig({
474
- contxtful: {customer: CUSTOMER, version: VERSION, sampling: {onAdRenderSucceeded: 1.0}},
998
+ contxtful: { customer: CUSTOMER, version: VERSION, sampling: { onAdRenderSucceeded: 1.0 } },
475
999
  });
476
1000
  const ajaxStub = sandbox.stub(ajax, 'ajax');
477
1001
  const beaconStub = sandbox.stub(ajax, 'sendBeacon').returns(false);
478
- spec.onAdRenderSucceeded({'customData': 'customvalue'});
1002
+ spec.onAdRenderSucceeded({ 'customData': 'customvalue' });
479
1003
  expect(ajaxStub.calledOnce).to.be.true;
480
1004
  expect(beaconStub.returned(false)).to.be.true;
481
1005
  });