Class: Puppeteer::Bidi::Core::BrowsingContext

Inherits:
EventEmitter
  • Object
show all
Includes:
Disposable::DisposableMixin
Defined in:
lib/puppeteer/bidi/core/browsing_context.rb,
sig/puppeteer/bidi/core/browsing_context.rbs

Overview

BrowsingContext represents a browsing context (tab, window, or iframe)

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Methods inherited from EventEmitter

#emit, #off, #on, #once, #remove_all_listeners

Constructor Details

#initialize(user_context, parent, id, url, original_opener, client_window) ⇒ BrowsingContext

Returns a new instance of BrowsingContext.

Parameters:

  • user_context (Object)
  • parent (Object)
  • id (Object)
  • url (Object)
  • original_opener (Object)
  • client_window (Object)


28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
# File 'lib/puppeteer/bidi/core/browsing_context.rb', line 28

def initialize(user_context, parent, id, url, original_opener, client_window)
  super()
  @user_context = user_context
  @parent = parent
  @id = id
  @url = url
  @original_opener = original_opener
  @window_id = client_window
  @reason = nil
  @disposables = Disposable::DisposableStack.new
  @children = {}
  @realms = {}
  @inflight_request_ids = {}
  @navigation = nil
  @emulation_state = { javascript_enabled: true }
  @client_hints_are_set = false
  @inflight_requests = 0
  @inflight_mutex = Thread::Mutex.new

  @default_realm = WindowRealm.from(self)
end

Instance Attribute Details

#default_realmObject (readonly)

Returns the value of attribute default_realm.

Returns:

  • (Object)


25
26
27
# File 'lib/puppeteer/bidi/core/browsing_context.rb', line 25

def default_realm
  @default_realm
end

#idObject (readonly)

Returns the value of attribute id.

Returns:

  • (Object)


25
26
27
# File 'lib/puppeteer/bidi/core/browsing_context.rb', line 25

def id
  @id
end

#inflight_requestsObject (readonly)

Returns the value of attribute inflight_requests.

Returns:

  • (Object)


25
26
27
# File 'lib/puppeteer/bidi/core/browsing_context.rb', line 25

def inflight_requests
  @inflight_requests
end

Returns the value of attribute navigation.

Returns:

  • (Object)


25
26
27
# File 'lib/puppeteer/bidi/core/browsing_context.rb', line 25

def navigation
  @navigation
end

#original_openerObject (readonly)

Returns the value of attribute original_opener.

Returns:

  • (Object)


25
26
27
# File 'lib/puppeteer/bidi/core/browsing_context.rb', line 25

def original_opener
  @original_opener
end

#parentObject (readonly)

Returns the value of attribute parent.

Returns:

  • (Object)


25
26
27
# File 'lib/puppeteer/bidi/core/browsing_context.rb', line 25

def parent
  @parent
end

#user_contextObject (readonly)

Returns the value of attribute user_context.

Returns:

  • (Object)


25
26
27
# File 'lib/puppeteer/bidi/core/browsing_context.rb', line 25

def user_context
  @user_context
end

#window_idObject (readonly)

Returns the value of attribute window_id.

Returns:

  • (Object)


25
26
27
# File 'lib/puppeteer/bidi/core/browsing_context.rb', line 25

def window_id
  @window_id
end

Class Method Details

.from(user_context, parent, id, url, original_opener, client_window) ⇒ BrowsingContext

Create a browsing context

Parameters:

  • user_context (UserContext)
  • parent (BrowsingContext, nil)
  • id (String)
  • url (String)
  • original_opener (String, nil)
  • client_window (String)

Returns:



19
20
21
22
23
# File 'lib/puppeteer/bidi/core/browsing_context.rb', line 19

def self.from(user_context, parent, id, url, original_opener, client_window)
  context = new(user_context, parent, id, url, original_opener, client_window)
  context.send(:initialize_context)
  context
end

Instance Method Details

#activateObject

Activate this browsing context

Returns:

  • (Object)


86
87
88
89
# File 'lib/puppeteer/bidi/core/browsing_context.rb', line 86

def activate
  raise BrowsingContextClosedError, @reason if closed?
  session.async_send_command('browsingContext.activate', { context: @id })
end

#add_intercept(**options) ⇒ Async::Task[String]

Add network intercept

Parameters:

  • options (Object)

Returns:



248
249
250
251
252
253
254
# File 'lib/puppeteer/bidi/core/browsing_context.rb', line 248

def add_intercept(**options)
  raise BrowsingContextClosedError, @reason if closed?
  Async do
    result = session.async_send_command('network.addIntercept', options.merge(contexts: [@id])).wait
    result['intercept']
  end
end

#add_interception(events) ⇒ void

This method returns an undefined value.

Add interception for this context

Parameters:

  • events (Array[String])


458
459
460
461
# File 'lib/puppeteer/bidi/core/browsing_context.rb', line 458

def add_interception(events)
  raise BrowsingContextClosedError, @reason if closed?
  session.subscribe(events, [@id])
end

#add_preload_script(function_declaration, **options) ⇒ Async::Task[String]

Add a preload script to this context

Parameters:

  • function_declaration (String)
  • options (Object)

Returns:



229
230
231
232
233
234
235
# File 'lib/puppeteer/bidi/core/browsing_context.rb', line 229

def add_preload_script(function_declaration, **options)
  raise BrowsingContextClosedError, @reason if closed?
  user_context.browser.add_preload_script(
    function_declaration,
    **options.merge(contexts: [self])
  )
end

#capture_screenshot(**options) ⇒ Async::Task[String]

Capture a screenshot

Parameters:

  • options (Object)

Returns:



117
118
119
120
121
122
123
# File 'lib/puppeteer/bidi/core/browsing_context.rb', line 117

def capture_screenshot(**options)
  raise BrowsingContextClosedError, @reason if closed?
  Async do
    result = session.async_send_command('browsingContext.captureScreenshot', options.merge(context: @id)).wait
    result['data']
  end
end

#childrenArray[BrowsingContext]

Get child browsing contexts

Returns:



65
66
67
# File 'lib/puppeteer/bidi/core/browsing_context.rb', line 65

def children
  @children.values
end

#close(prompt_unload: false) ⇒ Async::Task[void]

Close this browsing context

Parameters:

  • prompt_unload: (Boolean) (defaults to: false)

Returns:



139
140
141
142
143
144
145
# File 'lib/puppeteer/bidi/core/browsing_context.rb', line 139

def close(prompt_unload: false)
  raise BrowsingContextClosedError, @reason if closed?
  session.async_send_command('browsingContext.close', {
    context: @id,
    promptUnload: prompt_unload
  })
end

#closed?Object Also known as: disposed?

Check if the context is closed

Returns:

  • (Object)


51
52
53
# File 'lib/puppeteer/bidi/core/browsing_context.rb', line 51

def closed?
  !@reason.nil?
end

#create_window_realm(sandbox) ⇒ WindowRealm

Create a sandboxed window realm

Parameters:

  • sandbox (String)

Returns:



216
217
218
219
220
221
222
223
# File 'lib/puppeteer/bidi/core/browsing_context.rb', line 216

def create_window_realm(sandbox)
  raise BrowsingContextClosedError, @reason if closed?
  realm = WindowRealm.from(self, sandbox)
  realm.on(:worker) do |worker_realm|
    emit(:worker, worker_realm)
  end
  realm
end

Delete cookies

Parameters:

  • cookie_filters (Hash[String, untyped])

Returns:



308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
# File 'lib/puppeteer/bidi/core/browsing_context.rb', line 308

def delete_cookie(*cookie_filters)
  raise BrowsingContextClosedError, @reason if closed?
  Async do
    tasks = cookie_filters.map do |filter|
      session.async_send_command('storage.deleteCookies', {
        filter: filter,
        partition: {
          type: 'context',
          context: @id
        }
      })
    end

    AsyncUtils.promise_all(*tasks).wait unless tasks.empty?
  end
end

#disposeObject

Override dispose to emit :closed event before setting @disposed = true This is needed because EventEmitter#emit returns early if @disposed is true

Returns:

  • (Object)


465
466
467
468
469
470
471
472
# File 'lib/puppeteer/bidi/core/browsing_context.rb', line 465

def dispose
  return if disposed?

  @reason ||= 'Browsing context already closed, probably because the user context closed.'
  emit(:closed, @reason)

  super # This sets @disposed = true and calls perform_dispose
end

#dispose_children(reason) ⇒ Object

Parameters:

  • reason (Object)

Returns:

  • (Object)


681
682
683
684
685
686
# File 'lib/puppeteer/bidi/core/browsing_context.rb', line 681

def dispose_children(reason)
  @children.values.each do |child|
    next if child.closed?
    child.send(:dispose_context, reason)
  end
end

#dispose_context(reason) ⇒ Object

Parameters:

  • reason (Object)

Returns:

  • (Object)


688
689
690
691
692
693
# File 'lib/puppeteer/bidi/core/browsing_context.rb', line 688

def dispose_context(reason)
  # IMPORTANT: Set @reason AFTER calling dispose to avoid early return
  # dispose checks disposed? which is aliased to closed?, and closed? returns !@reason.nil?
  dispose
  @reason = reason
end

#finish_inflight_request(event) ⇒ Object

Parameters:

  • event (Object)

Returns:

  • (Object)


660
661
662
663
664
665
666
667
668
669
670
671
672
# File 'lib/puppeteer/bidi/core/browsing_context.rb', line 660

def finish_inflight_request(event)
  key = inflight_request_key(event)
  return unless key

  inflight = nil
  @inflight_mutex.synchronize do
    if @inflight_request_ids.delete(key)
      @inflight_requests -= 1
      inflight = @inflight_requests
    end
  end
  emit(:inflight_changed, { inflight: inflight }) if inflight
end

#get_cookies(**options) ⇒ Async::Task[Array[Hash[String, untyped]]]

Get cookies

Parameters:

  • options (Object)

Returns:



278
279
280
281
282
283
284
285
286
287
288
289
# File 'lib/puppeteer/bidi/core/browsing_context.rb', line 278

def get_cookies(**options)
  raise BrowsingContextClosedError, @reason if closed?
  params = options.dup
  params[:partition] = {
    type: 'context',
    context: @id
  }
  Async do
    result = session.async_send_command('storage.getCookies', params).wait
    result['cookies']
  end
end

#handle_user_prompt(**options) ⇒ Async::Task[untyped]

Handle a user prompt

Parameters:

  • options (Object)

Returns:



161
162
163
164
# File 'lib/puppeteer/bidi/core/browsing_context.rb', line 161

def handle_user_prompt(**options)
  raise BrowsingContextClosedError, @reason if closed?
  session.async_send_command('browsingContext.handleUserPrompt', options.merge(context: @id))
end

#inflight_request_key(event) ⇒ Object

Parameters:

  • event (Object)

Returns:

  • (Object)


674
675
676
677
678
679
# File 'lib/puppeteer/bidi/core/browsing_context.rb', line 674

def inflight_request_key(event)
  request_id = event.dig('request', 'request')
  return nil unless request_id

  [request_id, event['redirectCount'].to_i]
end

#initialize_contextObject

Returns:

  • (Object)


504
505
506
507
508
509
510
511
512
# File 'lib/puppeteer/bidi/core/browsing_context.rb', line 504

def initialize_context
  # Listen for user context closure
  @user_context.once(:closed) do |reason|
    dispose_context("Browsing context already closed: #{reason}")
  end

  # Listen for various browsing context events
  setup_event_listeners
end

#javascript_enabled?Boolean

Check if JavaScript is enabled

Returns:

  • (Boolean)


443
444
445
# File 'lib/puppeteer/bidi/core/browsing_context.rb', line 443

def javascript_enabled?
  @emulation_state[:javascript_enabled]
end

#locate_nodes(locator, start_nodes = []) ⇒ Async::Task[Array[Hash[String, untyped]]]

Locate nodes in the context

Parameters:

  • locator (Hash[String, untyped])
  • start_nodes (Array[Hash[String, untyped]]) (defaults to: [])

Returns:



413
414
415
416
417
418
419
420
421
422
423
424
425
# File 'lib/puppeteer/bidi/core/browsing_context.rb', line 413

def locate_nodes(locator, start_nodes = [])
  Async do
    raise BrowsingContextClosedError, @reason if closed?
    params = {
      context: @id,
      locator: locator
    }
    params[:startNodes] = start_nodes unless start_nodes.empty?

    result = session.async_send_command('browsingContext.locateNodes', params).wait
    result['nodes']
  end
end

Navigate to a URL

Parameters:

  • url (String)
  • wait: (String, nil) (defaults to: nil)

Returns:



95
96
97
98
99
100
101
102
103
104
# File 'lib/puppeteer/bidi/core/browsing_context.rb', line 95

def navigate(url, wait: nil)
  Async do
    raise BrowsingContextClosedError, @reason if closed?
    params = { context: @id, url: url }
    params[:wait] = wait if wait
    result = session.async_send_command('browsingContext.navigate', params).wait
    # URL will be updated via browsingContext.load event
    result
  end
end

#perform_actions(actions) ⇒ Async::Task[untyped]

Perform input actions

Parameters:

  • actions (Array[Hash[String, untyped]])

Returns:



188
189
190
191
192
193
194
# File 'lib/puppeteer/bidi/core/browsing_context.rb', line 188

def perform_actions(actions)
  raise BrowsingContextClosedError, @reason if closed?
  session.async_send_command('input.performActions', {
    context: @id,
    actions: actions
  })
end

#perform_disposeObject

Returns:

  • (Object)


476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
# File 'lib/puppeteer/bidi/core/browsing_context.rb', line 476

def perform_dispose
  dispose_children('Parent browsing context was disposed')

  begin
    @default_realm.dispose unless @default_realm&.disposed?
  rescue StandardError
    # Ignore realm disposal failures during shutdown
  end

  @realms.values.each do |realm|
    begin
      realm.dispose unless realm.disposed?
    rescue StandardError
      # Ignore per-realm cleanup errors
    end
  end
  @realms.clear

  @disposables.dispose
  super
end

Print to PDF

Parameters:

  • options (Object)

Returns:



128
129
130
131
132
133
134
# File 'lib/puppeteer/bidi/core/browsing_context.rb', line 128

def print(**options)
  raise BrowsingContextClosedError, @reason if closed?
  Async do
    result = session.async_send_command('browsingContext.print', options.merge(context: @id)).wait
    result['data']
  end
end

#realmsArray[WindowRealm]

Get all realms in this context

Returns:



71
72
73
# File 'lib/puppeteer/bidi/core/browsing_context.rb', line 71

def realms
  [@default_realm] + @realms.values
end

#release_actionsObject

Release input actions

Returns:

  • (Object)


197
198
199
200
# File 'lib/puppeteer/bidi/core/browsing_context.rb', line 197

def release_actions
  raise BrowsingContextClosedError, @reason if closed?
  session.async_send_command('input.releaseActions', { context: @id })
end

#reload(**options) ⇒ Async::Task[untyped]

Reload the page

Parameters:

  • options (Object)

Returns:



109
110
111
112
# File 'lib/puppeteer/bidi/core/browsing_context.rb', line 109

def reload(**options)
  raise BrowsingContextClosedError, @reason if closed?
  session.async_send_command('browsingContext.reload', options.merge(context: @id))
end

#remove_preload_script(script) ⇒ Async::Task[untyped]

Remove a preload script

Parameters:

  • script (String)

Returns:



240
241
242
243
# File 'lib/puppeteer/bidi/core/browsing_context.rb', line 240

def remove_preload_script(script)
  raise BrowsingContextClosedError, @reason if closed?
  user_context.browser.remove_preload_script(script)
end

#sessionObject

Returns:

  • (Object)


500
501
502
# File 'lib/puppeteer/bidi/core/browsing_context.rb', line 500

def session
  @user_context.browser.session
end

#set_cache_behavior(cache_behavior) ⇒ Async::Task[untyped]

Set cache behavior

Parameters:

  • cache_behavior (String)

Returns:



205
206
207
208
209
210
211
# File 'lib/puppeteer/bidi/core/browsing_context.rb', line 205

def set_cache_behavior(cache_behavior)
  raise BrowsingContextClosedError, @reason if closed?
  session.async_send_command('network.setCacheBehavior', {
    contexts: [@id],
    cacheBehavior: cache_behavior
  })
end

#set_client_hints_override(client_hints) ⇒ Async::Task[void]

Set client hints override

Parameters:

  • client_hints (Hash[String, untyped], nil)

Returns:



353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
# File 'lib/puppeteer/bidi/core/browsing_context.rb', line 353

def set_client_hints_override(client_hints)
  Async do
    raise BrowsingContextClosedError, @reason if closed?
    if client_hints.nil? && !@client_hints_are_set
      # Avoid calling unsupported command if no override has ever been set.
      next
    end

    @client_hints_are_set = true
    session.async_send_command('userAgentClientHints.setClientHintsOverride', {
      clientHints: client_hints,
      contexts: [@id]
    }).wait
  end
end

Set a cookie

Parameters:

  • cookie (Hash[String, untyped])

Returns:



294
295
296
297
298
299
300
301
302
303
# File 'lib/puppeteer/bidi/core/browsing_context.rb', line 294

def set_cookie(cookie)
  raise BrowsingContextClosedError, @reason if closed?
  session.async_send_command('storage.setCookie', {
    cookie: cookie,
    partition: {
      type: 'context',
      context: @id
    }
  })
end

#set_extra_http_headers(headers) ⇒ Async::Task[untyped]

Set extra HTTP headers for this context

Parameters:

  • headers (Hash[String, String])

Returns:



259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
# File 'lib/puppeteer/bidi/core/browsing_context.rb', line 259

def set_extra_http_headers(headers)
  raise BrowsingContextClosedError, @reason if closed?

  normalized = headers.map do |key, value|
    {
      name: key.to_s.downcase,
      value: { type: 'string', value: value.to_s }
    }
  end

  session.async_send_command('network.setExtraHeaders', {
    contexts: [@id],
    headers: normalized
  })
end

#set_files(element, files) ⇒ Async::Task[untyped]

Set files on an input element

Parameters:

  • element (Hash[String, untyped])
  • files (Array[String])

Returns:



400
401
402
403
404
405
406
407
# File 'lib/puppeteer/bidi/core/browsing_context.rb', line 400

def set_files(element, files)
  raise BrowsingContextClosedError, @reason if closed?
  session.async_send_command('input.setFiles', {
    context: @id,
    element: element,
    files: files
  })
end

#set_geolocation_override(**options) ⇒ Async::Task[untyped]

Set geolocation override

Parameters:

  • options (Object)

Returns:



328
329
330
331
332
333
334
335
336
# File 'lib/puppeteer/bidi/core/browsing_context.rb', line 328

def set_geolocation_override(**options)
  raise BrowsingContextClosedError, @reason if closed?
  raise 'Missing coordinates' unless options.key?(:coordinates)

  session.async_send_command('emulation.setGeolocationOverride', {
    coordinates: options[:coordinates],
    contexts: [@id]
  })
end

#set_javascript_enabled(enabled) ⇒ Async::Task[void]

Set JavaScript enabled state

Parameters:

  • enabled (Boolean)

Returns:



430
431
432
433
434
435
436
437
438
439
# File 'lib/puppeteer/bidi/core/browsing_context.rb', line 430

def set_javascript_enabled(enabled)
  Async do
    raise BrowsingContextClosedError, @reason if closed?
    session.async_send_command('emulation.setScriptingEnabled', {
      enabled: enabled ? nil : false,
      contexts: [@id]
    }).wait
    @emulation_state[:javascript_enabled] = enabled
  end
end

#set_locale_override(locale = nil) ⇒ Async::Task[void]

Set locale override

Parameters:

  • locale (String, nil) (defaults to: nil)

Returns:



387
388
389
390
391
392
393
394
# File 'lib/puppeteer/bidi/core/browsing_context.rb', line 387

def set_locale_override(locale = nil)
  raise BrowsingContextClosedError, @reason if closed?

  session.async_send_command("emulation.setLocaleOverride", {
    locale: locale,
    contexts: [@id]
  })
end

#set_timezone_override(timezone_id = nil) ⇒ Async::Task[untyped]

Set timezone override

Parameters:

  • timezone_id (String, nil) (defaults to: nil)

Returns:



372
373
374
375
376
377
378
379
380
381
382
# File 'lib/puppeteer/bidi/core/browsing_context.rb', line 372

def set_timezone_override(timezone_id = nil)
  raise BrowsingContextClosedError, @reason if closed?

  # Remove GMT prefix for interop between CDP and BiDi
  timezone_id = timezone_id&.sub(/^GMT/, '')

  session.async_send_command('emulation.setTimezoneOverride', {
    timezone: timezone_id,
    contexts: [@id]
  })
end

#set_touch_override(max_touch_points) ⇒ Async::Task[untyped]

Set touch override

Parameters:

  • max_touch_points (Integer, nil)

Returns:



177
178
179
180
181
182
183
# File 'lib/puppeteer/bidi/core/browsing_context.rb', line 177

def set_touch_override(max_touch_points)
  raise BrowsingContextClosedError, @reason if closed?
  session.async_send_command('emulation.setTouchOverride', {
    contexts: [@id],
    maxTouchPoints: max_touch_points
  })
end

#set_user_agent(user_agent) ⇒ Async::Task[void]

Set user agent override

Parameters:

  • user_agent (String, nil)

Returns:



341
342
343
344
345
346
347
348
# File 'lib/puppeteer/bidi/core/browsing_context.rb', line 341

def set_user_agent(user_agent)
  raise BrowsingContextClosedError, @reason if closed?

  session.async_send_command("emulation.setUserAgentOverride", {
    userAgent: user_agent,
    contexts: [@id]
  })
end

#set_viewport(**options) ⇒ Async::Task[untyped]

Set viewport

Parameters:

  • options (Object)

Returns:



169
170
171
172
# File 'lib/puppeteer/bidi/core/browsing_context.rb', line 169

def set_viewport(**options)
  raise BrowsingContextClosedError, @reason if closed?
  session.async_send_command('browsingContext.setViewport', options.merge(context: @id))
end

#setup_event_listenersObject

Returns:

  • (Object)


514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
# File 'lib/puppeteer/bidi/core/browsing_context.rb', line 514

def setup_event_listeners
  # Context destroyed
  session.on('browsingContext.contextDestroyed') do |info|
    next unless info['context'] == @id
    dispose_children('Parent browsing context was disposed')
    dispose_context('Browsing context already closed.')
  end

  # Child context created
  session.on('browsingContext.contextCreated') do |info|
    next unless info['parent'] == @id

    child_context = BrowsingContext.from(
      @user_context,
      self,
      info['context'],
      info['url'],
      info['originalOpener'],
      info['clientWindow'] || @window_id
    )

    @children[child_context.id] = child_context

    child_context.once(:closed) do
      @children.delete(child_context.id)
    end

    emit(:browsingcontext, child_context)
  end

  # History updated
  session.on('browsingContext.historyUpdated') do |info|
    next unless info['context'] == @id
    @url = info['url']
    emit(:history_updated, nil)
  end

  # Fragment navigated (anchor links, hash changes)
  session.on('browsingContext.fragmentNavigated') do |info|
    next unless info['context'] == @id
    @url = info['url']
    emit(:fragment_navigated, nil)
  end

  # DOM content loaded
  session.on('browsingContext.domContentLoaded') do |info|
    next unless info['context'] == @id
    @url = info['url']
    emit(:dom_content_loaded, nil)
  end

  # Page loaded
  session.on('browsingContext.load') do |info|
    next unless info['context'] == @id
    @url = info['url']
    emit(:load, nil)
  end

  # Navigation started
  session.on('browsingContext.navigationStarted') do |info|
    next unless info['context'] == @id

    # Skip if navigation hasn't finished
    next if @navigation && !@navigation.disposed?

    # Create new navigation
    @navigation = Navigation.from(self)

    # Wrap navigation in EventEmitter and register with disposables
    # This follows Puppeteer's pattern: new EventEmitter(this.#navigation)
    navigation_emitter = EventEmitter.new
    @disposables.use(navigation_emitter)

    # Listen for navigation completion events to update URL
    # Puppeteer: for (const eventName of ['fragment', 'failed', 'aborted'])
    [:fragment, :failed, :aborted].each do |event_name|
      @navigation.once(event_name) do |data|
        navigation_emitter.dispose
        @url = data[:url]
      end
    end

    # Emit navigation event for subscribers (e.g., Frame#wait_for_navigation)
    emit(:navigation, @navigation)
  end

  # Network events
  session.on('network.beforeRequestSent') do |event|
    next unless event['context'] == @id

    first_event_for_request = track_inflight_request(event)
    next if event['redirectCount'].to_i > 0
    next unless first_event_for_request

    request = Request.from(self, event)
    emit(:request, request)
  end

  session.on('network.responseCompleted') do |event|
    next unless event['context'] == @id

    finish_inflight_request(event)
  end

  session.on('network.fetchError') do |event|
    next unless event['context'] == @id

    finish_inflight_request(event)
  end

  # Log entries
  session.on('log.entryAdded') do |entry|
    next unless entry.dig('source', 'context') == @id
    emit(:log, entry)
  end

  # User prompts
  session.on('browsingContext.userPromptOpened') do |info|
    next unless info['context'] == @id
    # user_prompt = UserPrompt.from(self, info)
    # emit(:userprompt, user_prompt)
  end

  # File dialog
  session.on('input.fileDialogOpened') do |info|
    next unless info['context'] == @id
    emit(:filedialogopened, info)
  end
end

#subscribe(events) ⇒ void

This method returns an undefined value.

Subscribe to events for this context

Parameters:

  • events (Array[String])


450
451
452
453
# File 'lib/puppeteer/bidi/core/browsing_context.rb', line 450

def subscribe(events)
  raise BrowsingContextClosedError, @reason if closed?
  session.subscribe(events, [@id])
end

#topBrowsingContext

Get the top-level browsing context

Returns:



77
78
79
80
81
82
83
# File 'lib/puppeteer/bidi/core/browsing_context.rb', line 77

def top
  context = self
  while context.parent
    context = context.parent
  end
  context
end

#track_inflight_request(event) ⇒ Object

Parameters:

  • event (Object)

Returns:

  • (Object)


644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
# File 'lib/puppeteer/bidi/core/browsing_context.rb', line 644

def track_inflight_request(event)
  key = inflight_request_key(event)
  return false unless key

  inflight = nil
  @inflight_mutex.synchronize do
    unless @inflight_request_ids.key?(key)
      @inflight_request_ids[key] = true
      @inflight_requests += 1
      inflight = @inflight_requests
    end
  end
  emit(:inflight_changed, { inflight: inflight }) if inflight
  !inflight.nil?
end

#traverse_history(delta) ⇒ Async::Task[untyped]

Traverse history

Parameters:

  • delta (Integer)

Returns:



150
151
152
153
154
155
156
# File 'lib/puppeteer/bidi/core/browsing_context.rb', line 150

def traverse_history(delta)
  raise BrowsingContextClosedError, @reason if closed?
  session.async_send_command('browsingContext.traverseHistory', {
    context: @id,
    delta: delta
  })
end

#urlString

Get the current URL

Returns:

  • (String)


59
60
61
# File 'lib/puppeteer/bidi/core/browsing_context.rb', line 59

def url
  @url
end