@@ -274,4 +274,139 @@ describe('sevioBidAdapter', function () {
274274 expect ( requests [ 0 ] . data . keywords ) . to . have . property ( 'tokens' ) ;
275275 expect ( requests [ 0 ] . data . keywords . tokens ) . to . deep . equal ( [ 'keyword1' , 'keyword2' ] ) ;
276276 } ) ;
277+
278+ // Minimal env shims some helpers rely on
279+ Object . defineProperty ( window , 'visualViewport' , {
280+ value : { width : 1200 , height : 800 } ,
281+ configurable : true
282+ } ) ;
283+ Object . defineProperty ( window , 'screen' , {
284+ value : { width : 1920 , height : 1080 } ,
285+ configurable : true
286+ } ) ;
287+
288+ function mkBid ( overrides ) {
289+ return Object . assign ( {
290+ bidId : 'bid-1' ,
291+ bidder : 'sevio' ,
292+ params : { zone : 'zone-123' , referenceId : 'ref-abc' , keywords : [ 'k1' , 'k2' ] } ,
293+ mediaTypes : { banner : { sizes : [ [ 300 , 250 ] ] } } ,
294+ refererInfo : { page : 'https://example.com/page' , referer : 'https://referrer.example' } ,
295+ userIdAsEids : [ ]
296+ } , overrides || { } ) ;
297+ }
298+
299+ const baseBidderRequest = {
300+ timeout : 1200 ,
301+ refererInfo : { page : 'https://example.com/page' , referer : 'https://referrer.example' } ,
302+ gdprConsent : { consentString : 'TCF-STRING' } ,
303+ uspConsent : { uspString : '1NYN' } ,
304+ gppConsent : { consentString : 'GPP-STRING' } ,
305+ ortb2 : { device : { } , ext : { } }
306+ } ;
307+
308+ describe ( 'Sevio adapter helper coverage via buildRequests (JS)' , ( ) => {
309+ let stubs = [ ] ;
310+
311+ afterEach ( ( ) => {
312+ while ( stubs . length ) stubs . pop ( ) . restore ( ) ;
313+ document . title = '' ;
314+ document . head . innerHTML = '' ;
315+ try {
316+ Object . defineProperty ( navigator , 'connection' , { value : undefined , configurable : true } ) ;
317+ } catch ( e ) { }
318+ } ) ;
319+
320+ it ( 'getReferrerInfo → data.referer' , ( ) => {
321+ const out = spec . buildRequests ( [ mkBid ( ) ] , baseBidderRequest ) ;
322+ expect ( out ) . to . have . lengthOf ( 1 ) ;
323+ expect ( out [ 0 ] . data . referer ) . to . equal ( 'https://example.com/page' ) ;
324+ } ) ;
325+
326+ it ( 'getPageTitle prefers top.title; falls back to og:title (top document)' , ( ) => {
327+ window . top . document . title = 'Doc Title' ;
328+ let out = spec . buildRequests ( [ mkBid ( ) ] , baseBidderRequest ) ;
329+ expect ( out [ 0 ] . data . pageTitle ) . to . equal ( 'Doc Title' ) ;
330+
331+ window . top . document . title = '' ;
332+ const meta = window . top . document . createElement ( 'meta' ) ;
333+ meta . setAttribute ( 'property' , 'og:title' ) ;
334+ meta . setAttribute ( 'content' , 'OG Title' ) ;
335+ window . top . document . head . appendChild ( meta ) ;
336+
337+ out = spec . buildRequests ( [ mkBid ( ) ] , baseBidderRequest ) ;
338+ expect ( out [ 0 ] . data . pageTitle ) . to . equal ( 'OG Title' ) ;
339+
340+ meta . remove ( ) ;
341+ } ) ;
342+
343+ it ( 'getPageTitle cross-origin fallback (window.top throws) uses local document.*' , function ( ) {
344+ document . title = 'Local Title' ;
345+
346+ // In jsdom, window.top === window; try to simulate cross-origin by throwing from getter.
347+ let restored = false ;
348+ try {
349+ const original = Object . getOwnPropertyDescriptor ( window , 'top' ) ;
350+ Object . defineProperty ( window , 'top' , {
351+ configurable : true ,
352+ get ( ) { throw new Error ( 'cross-origin' ) ; }
353+ } ) ;
354+ const out = spec . buildRequests ( [ mkBid ( ) ] , baseBidderRequest ) ;
355+ expect ( out [ 0 ] . data . pageTitle ) . to . equal ( 'Local Title' ) ;
356+ Object . defineProperty ( window , 'top' , original ) ;
357+ restored = true ;
358+ } catch ( e ) {
359+ // Environment didn’t allow redefining window.top; skip this case
360+ this . skip ( ) ;
361+ } finally {
362+ if ( ! restored ) {
363+ try { Object . defineProperty ( window , 'top' , { value : window , configurable : true } ) ; } catch ( e ) { }
364+ }
365+ }
366+ } ) ;
367+
368+ it ( 'computeTTFB via navigation entries (top.performance) and cached within call' , ( ) => {
369+ const perfTop = window . top . performance ;
370+
371+ const original = perfTop . getEntriesByType ;
372+ Object . defineProperty ( perfTop , 'getEntriesByType' , {
373+ configurable : true , writable : true ,
374+ value : ( type ) => ( type === 'navigation' ? [ { responseStart : 152 , requestStart : 100 } ] : [ ] )
375+ } ) ;
376+
377+ const out = spec . buildRequests ( [ mkBid ( { bidId : 'A' } ) , mkBid ( { bidId : 'B' } ) ] , baseBidderRequest ) ;
378+ expect ( out ) . to . have . lengthOf ( 2 ) ;
379+ expect ( out [ 0 ] . data . timeToFirstByte ) . to . equal ( '52' ) ;
380+ expect ( out [ 1 ] . data . timeToFirstByte ) . to . equal ( '52' ) ;
381+
382+ Object . defineProperty ( perfTop , 'getEntriesByType' , { configurable : true , writable : true , value : original } ) ;
383+ } ) ;
384+
385+ it ( 'computeTTFB falls back to top.performance.timing when no navigation entries' , ( ) => {
386+ const perfTop = window . top . performance ;
387+ const originalGetEntries = perfTop . getEntriesByType ;
388+ const originalTimingDesc = Object . getOwnPropertyDescriptor ( perfTop , 'timing' ) ;
389+
390+ Object . defineProperty ( perfTop , 'getEntriesByType' , {
391+ configurable : true , writable : true , value : ( ) => [ ]
392+ } ) ;
393+
394+ Object . defineProperty ( perfTop , 'timing' , {
395+ configurable : true ,
396+ value : { responseStart : 250 , requestStart : 200 }
397+ } ) ;
398+
399+ const out = spec . buildRequests ( [ mkBid ( ) ] , baseBidderRequest ) ;
400+ expect ( out [ 0 ] . data . timeToFirstByte ) . to . equal ( '50' ) ;
401+
402+ Object . defineProperty ( perfTop , 'getEntriesByType' , {
403+ configurable : true , writable : true , value : originalGetEntries
404+ } ) ;
405+ if ( originalTimingDesc ) {
406+ Object . defineProperty ( perfTop , 'timing' , originalTimingDesc ) ;
407+ } else {
408+ Object . defineProperty ( perfTop , 'timing' , { configurable : true , value : undefined } ) ;
409+ }
410+ } ) ;
411+ } ) ;
277412} ) ;
0 commit comments