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.

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)

: Browser

Returns:



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

def browser
  @browser
end

#user_contextCore::UserContext (readonly)

: 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.



320
321
322
323
324
325
326
327
328
329
330
331
332
333
# File 'lib/puppeteer/bidi/browser_context.rb', line 320

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



337
338
339
340
341
# File 'lib/puppeteer/bidi/browser_context.rb', line 337

def close
  return if closed?

  @user_context.remove.wait
end

#closed?Boolean

Check if context is closed

Returns:

  • (Boolean)


345
346
347
# File 'lib/puppeteer/bidi/browser_context.rb', line 345

def closed?
  @user_context.disposed?
end

Parameters:

  • cookie (Object)
  • raw_filter (Object)

Returns:

  • (Boolean)


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
392
393
394
# File 'lib/puppeteer/bidi/browser_context.rb', line 364

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.

Returns:

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


140
141
142
143
144
145
146
# File 'lib/puppeteer/bidi/browser_context.rb', line 140

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)


396
397
398
399
400
# File 'lib/puppeteer/bidi/browser_context.rb', line 396

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.

Parameters:

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


198
199
200
201
202
203
204
205
206
207
208
# File 'lib/puppeteer/bidi/browser_context.rb', line 198

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.

Parameters:

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


214
215
216
217
218
219
220
221
222
223
# File 'lib/puppeteer/bidi/browser_context.rb', line 214

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)

Parameters:

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

Returns:



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

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

Parameters:

  • event (Symbol, String)


76
77
78
79
# File 'lib/puppeteer/bidi/browser_context.rb', line 76

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

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

Register an event listener

Parameters:

  • event (Symbol, String)

Yields:

Yield Parameters:

  • arg0 (Object)

Yield Returns:

  • (void)

Returns:



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

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

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

Register a one-time event listener

Parameters:

  • event (Symbol, String)

Yields:

Yield Parameters:

  • arg0 (Object)

Yield Returns:

  • (void)

Returns:



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

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

#override_permissions(origin, permissions) ⇒ void

This method returns an undefined value.

Override permissions for an origin

Parameters:

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


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

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

Parameters:

Returns:



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
255
256
257
# File 'lib/puppeteer/bidi/browser_context.rb', line 228

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

Returns:



104
105
106
107
108
109
110
111
112
113
114
# File 'lib/puppeteer/bidi/browser_context.rb', line 104

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.

Parameters:

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


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
190
191
192
# File 'lib/puppeteer/bidi/browser_context.rb', line 152

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.

Parameters:

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


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
314
315
316
# File 'lib/puppeteer/bidi/browser_context.rb', line 289

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

Parameters:

Returns:



353
354
355
356
357
358
359
360
361
362
# File 'lib/puppeteer/bidi/browser_context.rb', line 353

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.

Returns:



118
119
120
121
122
# File 'lib/puppeteer/bidi/browser_context.rb', line 118

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.

Parameters:

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

Yields:

Yield Parameters:

Yield Returns:

  • (boolish)

Returns:



128
129
130
131
132
133
134
135
136
# File 'lib/puppeteer/bidi/browser_context.rb', line 128

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