Class: Puppeteer::Bidi::BrowserContext

Inherits:
Object
  • Object
show all
Defined in:
lib/puppeteer/bidi/browser_context.rb,
sig/puppeteer/bidi/browser_context.rbs

Overview

BrowserContext represents an isolated browsing session This is a high-level wrapper around Core::UserContext

Constant Summary collapse

WEB_PERMISSION_TO_PROTOCOL_PERMISSION =

Maps web permission names to protocol permission names Based on Puppeteer's WEB_PERMISSION_TO_PROTOCOL_PERMISSION

Returns:

  • (Object)
{
  'accelerometer' => 'sensors',
  'ambient-light-sensor' => 'sensors',
  'background-sync' => 'backgroundSync',
  'camera' => 'videoCapture',
  'clipboard-read' => 'clipboardReadWrite',
  'clipboard-sanitized-write' => 'clipboardSanitizedWrite',
  'clipboard-write' => 'clipboardReadWrite',
  'geolocation' => 'geolocation',
  'gyroscope' => 'sensors',
  'idle-detection' => 'idleDetection',
  'keyboard-lock' => 'keyboardLock',
  'magnetometer' => 'sensors',
  'microphone' => 'audioCapture',
  'midi' => 'midi',
  'midi-sysex' => 'midiSysex',
  'notifications' => 'notifications',
  'payment-handler' => 'paymentHandler',
  'persistent-storage' => 'durableStorage',
  'pointer-lock' => 'pointerLock'
}.freeze

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(browser, user_context) ⇒ BrowserContext

Returns a new instance of BrowserContext.

RBS:

  • browser: Browser -- Parent browser instance

  • user_context: Core::UserContext -- Associated user context

  • return: void

Parameters:



41
42
43
44
45
46
47
48
49
50
51
52
# File 'lib/puppeteer/bidi/browser_context.rb', line 41

def initialize(browser, user_context)
  @browser = browser
  @user_context = user_context
  @pages = {}
  @frame_targets = {}
  @overrides = []
  @emitter = Core::EventEmitter.new

  @user_context.browsing_contexts.each { |browsing_context| page_for(browsing_context) }
  @user_context.on(:browsingcontext) { |browsing_context| page_for(browsing_context) }
  @user_context.once(:closed) { @emitter.dispose }
end

Instance Attribute Details

#browserBrowser (readonly)

Signature:

  • Browser

Returns:



36
37
38
# File 'lib/puppeteer/bidi/browser_context.rb', line 36

def browser
  @browser
end

#user_contextCore::UserContext (readonly)

Signature:

  • Core::UserContext

Returns:



35
36
37
# File 'lib/puppeteer/bidi/browser_context.rb', line 35

def user_context
  @user_context
end

Instance Method Details

#clear_permission_overridesvoid

This method returns an undefined value.

Clear permissions set through #override_permissions.

RBS:

  • return: void



317
318
319
320
321
322
323
324
325
326
327
328
329
330
# File 'lib/puppeteer/bidi/browser_context.rb', line 317

def clear_permission_overrides
  tasks = @overrides.map do |override|
    lambda do
      begin
        @user_context.set_permissions(override[:origin], { name: override[:permission] }, 'prompt').wait
      rescue StandardError => error
        debug_error(error)
      end
    end
  end

  @overrides = []
  AsyncUtils.await_promise_all(*tasks) unless tasks.empty?
end

#closevoid

This method returns an undefined value.

Close the browser context

RBS:

  • return: void



334
335
336
337
338
# File 'lib/puppeteer/bidi/browser_context.rb', line 334

def close
  return if closed?

  @user_context.remove.wait
end

#closed?Boolean

Check if context is closed

RBS:

  • return: bool -- Whether the context is closed

Returns:

  • (Boolean)


342
343
344
# File 'lib/puppeteer/bidi/browser_context.rb', line 342

def closed?
  @user_context.disposed?
end

Parameters:

  • cookie (Object)
  • raw_filter (Object)

Returns:

  • (Boolean)


361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
# File 'lib/puppeteer/bidi/browser_context.rb', line 361

def cookie_matches_filter?(cookie, raw_filter)
  filter = CookieUtils.normalize_cookie_input(raw_filter)
  return false unless filter["name"] == cookie["name"]

  return true if filter.key?("domain") && filter["domain"] == cookie["domain"]
  return true if filter.key?("path") && filter["path"] == cookie["path"]

  if filter.key?("partitionKey") && cookie.key?("partitionKey")
    cookie_partition = cookie["partitionKey"]
    unless cookie_partition.is_a?(Hash)
      raise Error, "Unexpected string partition key"
    end

    filter_partition = filter["partitionKey"]
    if filter_partition.is_a?(String)
      return true if filter_partition == cookie_partition["sourceOrigin"]
    elsif filter_partition.is_a?(Hash)
      normalized_partition = CookieUtils.normalize_cookie_input(filter_partition)
      return true if normalized_partition["sourceOrigin"] == cookie_partition["sourceOrigin"]
    end
  end

  if filter.key?("url")
    url = URI.parse(filter["url"])
    url_path = url.path
    url_path = "/" if url_path.nil? || url_path.empty?
    return true if url.host == cookie["domain"] && url_path == cookie["path"]
  end

  true
end

#cookiesArray[Hash[String, untyped]]

Get all cookies in this context.

RBS:

  • return: Array[Hash[String, untyped]] -- Cookies

Returns:

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


137
138
139
140
141
142
143
# File 'lib/puppeteer/bidi/browser_context.rb', line 137

def cookies
  return [] if closed?

  @user_context.get_cookies.wait.map do |cookie|
    CookieUtils.bidi_to_puppeteer_cookie(cookie, return_composite_partition_key: true)
  end
end

#debug_error(error) ⇒ Object

Parameters:

  • error (Object)

Returns:

  • (Object)


393
394
395
396
397
# File 'lib/puppeteer/bidi/browser_context.rb', line 393

def debug_error(error)
  return unless ENV['DEBUG_BIDI_COMMAND']

  warn(error.full_message)
end

This method returns an undefined value.

Delete cookies in this context.

RBS:

  • *cookies: Array[Hash[String, untyped]] -- Cookies to delete

  • **cookie: untyped -- Single cookie via keyword arguments

  • return: void

Parameters:

  • cookies (Array[Hash[String, untyped]])
  • cookie (Object)


195
196
197
198
199
200
201
202
203
204
205
# File 'lib/puppeteer/bidi/browser_context.rb', line 195

def delete_cookie(*cookies, **cookie)
  cookies = cookies.dup
  cookies << cookie unless cookie.empty?

  delete_candidates = cookies.map do |raw_cookie|
    normalized_cookie = CookieUtils.normalize_cookie_input(raw_cookie)
    normalized_cookie.merge("expires" => 1)
  end

  set_cookie(*delete_candidates)
end

#delete_matching_cookies(*filters, **filter) ⇒ void

This method returns an undefined value.

Delete cookies matching the provided filters.

RBS:

  • *filters: Array[Hash[String, untyped]] -- Cookie filters

  • **filter: untyped -- Single cookie filter via keyword arguments

  • return: void

Parameters:

  • filters (Array[Hash[String, untyped]])
  • filter (Object)


211
212
213
214
215
216
217
218
219
220
# File 'lib/puppeteer/bidi/browser_context.rb', line 211

def delete_matching_cookies(*filters, **filter)
  filters = filters.dup
  filters << filter unless filter.empty?

  cookies_to_delete = cookies.select do |cookie|
    filters.any? { |filter_entry| cookie_matches_filter?(cookie, filter_entry) }
  end

  delete_cookie(*cookies_to_delete)
end

#new_page(background: nil, type: nil, window_bounds: nil) ⇒ Page

Create a new page (tab/window)

RBS:

  • background: bool? -- Whether to open the page in background

  • type: String? -- 'tab' or 'window'

  • window_bounds: Hash[Symbol | String, untyped]? -- Initial window bounds for window pages

  • return: Page -- New page instance

Parameters:

  • background: (Boolean, nil) (defaults to: nil)
  • type: (String, nil) (defaults to: nil)
  • window_bounds: (Hash[Symbol | String, untyped], nil) (defaults to: nil)

Returns:



83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
# File 'lib/puppeteer/bidi/browser_context.rb', line 83

def new_page(background: nil, type: nil, window_bounds: nil)
  create_type = type.to_s == 'window' ? 'window' : 'tab'
  browsing_context = @user_context.create_browsing_context(create_type, background: background)
  page = page_for(browsing_context)

  if create_type == 'window' && window_bounds
    begin
      @browser.set_window_bounds(browsing_context.window_id, window_bounds)
    rescue StandardError => error
      debug_error(error)
    end
  end

  page
end

#off(event, &block) ⇒ void

This method returns an undefined value.

Remove an event listener

RBS:

  • event: Symbol | String -- Event name

  • &block: ((untyped) -> void)? -- Event handler to remove

  • return: void

Parameters:

  • event (Symbol, String)


74
75
76
# File 'lib/puppeteer/bidi/browser_context.rb', line 74

def off(event, &block)
  @emitter.off(event, &block)
end

#on(event) {|arg0| ... } ⇒ void

This method returns an undefined value.

Register an event listener

RBS:

  • event: Symbol | String -- Event name

  • &block: (untyped) -> void -- Event handler

  • return: void

Parameters:

  • event (Symbol, String)

Yields:

Yield Parameters:

  • arg0 (Object)

Yield Returns:

  • (void)


58
59
60
# File 'lib/puppeteer/bidi/browser_context.rb', line 58

def on(event, &block)
  @emitter.on(event, &block)
end

#once(event) {|arg0| ... } ⇒ void

This method returns an undefined value.

Register a one-time event listener

RBS:

  • event: Symbol | String -- Event name

  • &block: (untyped) -> void -- Event handler

  • return: void

Parameters:

  • event (Symbol, String)

Yields:

Yield Parameters:

  • arg0 (Object)

Yield Returns:

  • (void)


66
67
68
# File 'lib/puppeteer/bidi/browser_context.rb', line 66

def once(event, &block)
  @emitter.once(event, &block)
end

#override_permissions(origin, permissions) ⇒ void

This method returns an undefined value.

Override permissions for an origin

RBS:

  • origin: String -- Origin URL

  • permissions: Array[String] -- Permissions to grant

  • return: void

Parameters:

  • origin (String)
  • permissions (Array[String])


260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
# File 'lib/puppeteer/bidi/browser_context.rb', line 260

def override_permissions(origin, permissions)
  # Validate all permissions are known
  permissions_set = permissions.map do |permission|
    protocol_permission = WEB_PERMISSION_TO_PROTOCOL_PERMISSION[permission.to_s]
    raise ArgumentError, "Unknown permission: #{permission}" unless protocol_permission

    permission.to_s
  end.to_set

  # Set each permission
  WEB_PERMISSION_TO_PROTOCOL_PERMISSION.each_key do |permission|
    state = permissions_set.include?(permission) ? 'granted' : 'denied'
    begin
      @user_context.set_permissions(origin, { name: permission }, state).wait
      @overrides << { origin: origin, permission: permission }
    rescue StandardError
      # Ignore errors for denied permissions (some may not be supported)
      raise if permissions_set.include?(permission)
    end
  end
end

#page_for(browsing_context) ⇒ Page

Get or create a Page for the given browsing context

RBS:

  • browsing_context: Core::BrowsingContext -- Browsing context

  • return: Page -- Page instance

Parameters:

Returns:



225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
# File 'lib/puppeteer/bidi/browser_context.rb', line 225

def page_for(browsing_context)
  @pages[browsing_context.id] ||= begin
    page = Page.new(self, browsing_context)
    page_target = page.target

    page.on(:frameattached) do |frame|
      @emitter.emit(:targetcreated, target_for_frame(frame))
    end

    page.on(:framenavigated) do |frame|
      target = frame.parent_frame ? target_for_frame(frame) : page_target
      @emitter.emit(:targetchanged, target)
    end

    page.on(:framedetached) do |frame|
      next unless frame.parent_frame

      target = @frame_targets.delete(frame.browsing_context.id)
      @emitter.emit(:targetdestroyed, target) if target
    end

    browsing_context.once(:closed) do
      @pages.delete(browsing_context.id)
      @emitter.emit(:targetdestroyed, page_target)
    end

    @emitter.emit(:targetcreated, page_target)
    page
  end
end

#pagesArray[Page]

Get all pages in this context

RBS:

  • return: Array[Page] -- All pages

Returns:



101
102
103
104
105
106
107
108
109
110
111
# File 'lib/puppeteer/bidi/browser_context.rb', line 101

def pages
  return [] if closed?

  # Return pages for all currently-known top-level browsing contexts.
  # Browsing contexts are synchronized from `browsingContext.getTree` during browser/session
  # initialization, so this allows `Puppeteer::Bidi.connect` to expose existing pages without
  # requiring an explicit enumeration via `wait_for_target`.
  @user_context.browsing_contexts
               .reject(&:disposed?)
               .map { |browsing_context| page_for(browsing_context) }
end

This method returns an undefined value.

Set cookies in this context.

RBS:

  • *cookies: Array[Hash[String, untyped]] -- Cookie data

  • **cookie: untyped -- Single cookie via keyword arguments

  • return: void

Parameters:

  • cookies (Array[Hash[String, untyped]])
  • cookie (Object)


149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
# File 'lib/puppeteer/bidi/browser_context.rb', line 149

def set_cookie(*cookies, **cookie)
  cookies = cookies.dup
  cookies << cookie unless cookie.empty?

  tasks = cookies.map do |raw_cookie|
    normalized_cookie = CookieUtils.normalize_cookie_input(raw_cookie)
    domain = normalized_cookie["domain"]
    if domain.nil?
      raise ArgumentError, "At least one of the url and domain needs to be specified"
    end

    bidi_cookie = {
      "domain" => domain,
      "name" => normalized_cookie["name"],
      "value" => { "type" => "string", "value" => normalized_cookie["value"] },
    }
    bidi_cookie["path"] = normalized_cookie["path"] if normalized_cookie.key?("path")
    bidi_cookie["httpOnly"] = normalized_cookie["httpOnly"] if normalized_cookie.key?("httpOnly")
    bidi_cookie["secure"] = normalized_cookie["secure"] if normalized_cookie.key?("secure")
    if normalized_cookie.key?("sameSite") && !normalized_cookie["sameSite"].nil?
      bidi_cookie["sameSite"] = CookieUtils.convert_cookies_same_site_cdp_to_bidi(
        normalized_cookie["sameSite"]
      )
    end
    expiry = CookieUtils.convert_cookies_expiry_cdp_to_bidi(normalized_cookie["expires"])
    bidi_cookie["expiry"] = expiry unless expiry.nil?
    bidi_cookie.merge!(CookieUtils.cdp_specific_cookie_properties_from_puppeteer_to_bidi(
                         normalized_cookie,
                         "sourceScheme",
                         "priority",
                         "url"
                       ))

    partition_key = CookieUtils.convert_cookies_partition_key_from_puppeteer_to_bidi(
      normalized_cookie["partitionKey"]
    )
    -> { @user_context.set_cookie(bidi_cookie, source_origin: partition_key).wait }
  end

  AsyncUtils.await_promise_all(*tasks) unless tasks.empty?
end

#set_permission(origin, *permissions) ⇒ void

This method returns an undefined value.

Set permission states for one or more permission descriptors.

RBS:

  • origin: String | Symbol -- Origin URL (must not be '*')

  • *permissions: Hash[Symbol | String, untyped] -- Permission descriptors with states

  • return: void

Parameters:

  • origin (String, Symbol)
  • permissions (Hash[Symbol | String, untyped])


286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
# File 'lib/puppeteer/bidi/browser_context.rb', line 286

def set_permission(origin, *permissions)
  if origin.to_s == '*'
    raise UnsupportedOperationError, 'Origin (*) is not supported by WebDriver BiDi'
  end

  tasks = permissions.map do |permission_entry|
    descriptor = permission_entry[:permission] || permission_entry['permission']
    state = permission_entry[:state] || permission_entry['state']
    raise ArgumentError, 'permission descriptor is required' unless descriptor.is_a?(Hash)
    raise ArgumentError, 'permission state is required' if state.nil?
    descriptor = descriptor.transform_keys(&:to_sym)

    if descriptor[:allowWithoutSanitization] || descriptor[:allow_without_sanitization]
      raise UnsupportedOperationError, 'allowWithoutSanitization is not supported by WebDriver BiDi'
    end
    if descriptor[:panTiltZoom] || descriptor[:pan_tilt_zoom]
      raise UnsupportedOperationError, 'panTiltZoom is not supported by WebDriver BiDi'
    end
    if descriptor[:userVisibleOnly] || descriptor[:user_visible_only]
      raise UnsupportedOperationError, 'userVisibleOnly is not supported by WebDriver BiDi'
    end
    raise ArgumentError, 'permission name is required' if descriptor[:name].nil?

    -> { @user_context.set_permissions(origin.to_s, { name: descriptor[:name] }, state.to_s).wait }
  end

  AsyncUtils.await_promise_all(*tasks) unless tasks.empty?
end

#target_for_frame(frame) ⇒ FrameTarget

RBS:

  • frame: Frame -- Frame to get target for

  • return: FrameTarget -- Frame target

Parameters:

Returns:



350
351
352
353
354
355
356
357
358
359
# File 'lib/puppeteer/bidi/browser_context.rb', line 350

def target_for_frame(frame)
  context_id = frame.browsing_context.id
  @frame_targets[context_id] ||= begin
    target = FrameTarget.new(frame)
    frame.browsing_context.once(:closed) do
      @frame_targets.delete(context_id)
    end
    target
  end
end

#targetsArray[PageTarget | FrameTarget]

Get all known targets in this browser context.

RBS:

  • return: Array[PageTarget | FrameTarget] -- Known targets

Returns:



115
116
117
118
119
# File 'lib/puppeteer/bidi/browser_context.rb', line 115

def targets
  pages.flat_map do |page|
    [page.target] + page.frames.drop(1).map { |frame| target_for_frame(frame) }
  end
end

#wait_for_target(timeout: nil) {|arg0| ... } ⇒ PageTarget, FrameTarget

Wait until a target in this context satisfies the predicate.

RBS:

  • timeout: Integer? -- Timeout in milliseconds (default: 30000)

  • &predicate: (PageTarget | FrameTarget) -> boolish -- Predicate evaluated against each target

  • return: PageTarget | FrameTarget -- Matching target

Parameters:

  • timeout: (Integer, nil) (defaults to: nil)

Yields:

Yield Parameters:

Yield Returns:

  • (boolish)

Returns:



125
126
127
128
129
130
131
132
133
# File 'lib/puppeteer/bidi/browser_context.rb', line 125

def wait_for_target(timeout: nil, &predicate)
  predicate ||= ->(_target) { true }

  browser.wait_for_target(timeout: timeout) do |target|
    (target.is_a?(PageTarget) || target.is_a?(FrameTarget)) &&
      target.browser_context == self &&
      predicate.call(target)
  end #: PageTarget | FrameTarget
end