puppeteer-ruby 0.0.18 → 0.0.23

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 (41) hide show
  1. checksums.yaml +4 -4
  2. data/.circleci/config.yml +24 -1
  3. data/.github/workflows/reviewdog.yml +1 -1
  4. data/.rubocop.yml +50 -3
  5. data/Dockerfile +9 -0
  6. data/README.md +38 -0
  7. data/docker-compose.yml +34 -0
  8. data/lib/puppeteer.rb +15 -11
  9. data/lib/puppeteer/browser.rb +19 -26
  10. data/lib/puppeteer/browser_context.rb +48 -49
  11. data/lib/puppeteer/browser_runner.rb +20 -6
  12. data/lib/puppeteer/cdp_session.rb +21 -7
  13. data/lib/puppeteer/concurrent_ruby_utils.rb +18 -5
  14. data/lib/puppeteer/connection.rb +32 -13
  15. data/lib/puppeteer/debug_print.rb +1 -1
  16. data/lib/puppeteer/define_async_method.rb +1 -1
  17. data/lib/puppeteer/devices.rb +998 -849
  18. data/lib/puppeteer/dialog.rb +34 -0
  19. data/lib/puppeteer/dom_world.rb +2 -2
  20. data/lib/puppeteer/element_handle.rb +18 -1
  21. data/lib/puppeteer/env.rb +5 -0
  22. data/lib/puppeteer/event_callbackable.rb +4 -0
  23. data/lib/puppeteer/events.rb +184 -0
  24. data/lib/puppeteer/exception_details.rb +38 -0
  25. data/lib/puppeteer/frame.rb +1 -3
  26. data/lib/puppeteer/frame_manager.rb +20 -16
  27. data/lib/puppeteer/geolocation.rb +24 -0
  28. data/lib/puppeteer/keyboard/us_keyboard_layout.rb +2 -2
  29. data/lib/puppeteer/launcher.rb +11 -2
  30. data/lib/puppeteer/launcher/base.rb +14 -4
  31. data/lib/puppeteer/launcher/browser_options.rb +2 -1
  32. data/lib/puppeteer/launcher/chrome.rb +5 -9
  33. data/lib/puppeteer/launcher/firefox.rb +385 -0
  34. data/lib/puppeteer/lifecycle_watcher.rb +6 -6
  35. data/lib/puppeteer/network_manager.rb +6 -6
  36. data/lib/puppeteer/page.rb +87 -103
  37. data/lib/puppeteer/remote_object.rb +12 -1
  38. data/lib/puppeteer/target.rb +2 -2
  39. data/lib/puppeteer/version.rb +1 -1
  40. data/puppeteer-ruby.gemspec +1 -1
  41. metadata +11 -4
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 63cde4d139f1dc95710efb059310822219b905ef4b44ec8a1347b4bdc97a6b2e
4
- data.tar.gz: '0989de5d246bb1c2bcb5ab625eb0702f608ec6ec667db9bbcf4282cf419314fa'
3
+ metadata.gz: 133c14dccb0da46cc01bff747bb2e36c1de1f7619ee4a8a898e798b3eb3947af
4
+ data.tar.gz: a7cc95948ddef2b45cc3b4a8faa82497334daeb1e47d92c97a7cbcbf9dccd887
5
5
  SHA512:
6
- metadata.gz: 96aaf3dc540e160dd983660f2ea4fa10a8c3a2126e9c56f57f9c7a11c31c956376f556473c2d6c591b4cf4253c92e91055cc564e1910fe6dbaf3eb8244d2e852
7
- data.tar.gz: c2195746ce0ed09fb2be8e66cb842cc2fb9487c51cb2232e51f3970df0234aec97fce173627bbedd1c4d113cd82154c134a69d0f9eb02c23826ab0bc0ad7ee18
6
+ metadata.gz: de40a672ecbf7089e43463497bd877ed671e366ae022d6224bef0068c9ecbc5a949d4649454348af8d9823abf0e0effe84255ce3e73f8bd6f13c2d4ce2dd514e
7
+ data.tar.gz: 96821b3ec521338f6c2a08c31a65113acb1aa808e1f50b9fece78bcdcc19cb6f4072b2dd6d778a5a413f47733b1efa7d3f9ded85fdd0e0dce6c1729f53be47ab
@@ -5,7 +5,7 @@ orbs:
5
5
  jobs:
6
6
  rspec:
7
7
  docker:
8
- - image: circleci/ruby:2.6.3-stretch-node-browsers
8
+ - image: circleci/ruby:2.6.6-buster-node-browsers
9
9
  executor: ruby/default
10
10
  steps:
11
11
  - checkout
@@ -18,6 +18,28 @@ jobs:
18
18
  --out test_results/rspec.xml \
19
19
  --format documentation
20
20
 
21
+ rspec_firefox:
22
+ docker:
23
+ - image: circleci/ruby:2.6.6-buster-node-browsers
24
+ executor: ruby/default
25
+ steps:
26
+ - checkout
27
+ - ruby/bundle-install
28
+ - run:
29
+ name: install firefox-nightly
30
+ command: |
31
+ wget -O nightly.tar.bz2 "https://download.mozilla.org/?product=firefox-nightly-latest-ssl&os=linux64&lang=en-US"
32
+ tar xf nightly.tar.bz2
33
+ - run:
34
+ name: rspec
35
+ command: |
36
+ DEBUG=1 PUPPETEER_PRODUCT_RSPEC=firefox \
37
+ PUPPETEER_EXECUTABLE_PATH_RSPEC=${CIRCLE_WORKING_DIRECTORY/#\~/$HOME}/firefox/firefox \
38
+ bundle exec rspec --profile 10 \
39
+ --format RspecJunitFormatter \
40
+ --out test_results/rspec.xml \
41
+ --format documentation spec/integration/
42
+
21
43
  deploy:
22
44
  docker:
23
45
  - image: circleci/ruby:2.6.3-stretch-node
@@ -49,6 +71,7 @@ workflows:
49
71
  ci:
50
72
  jobs:
51
73
  - rspec
74
+ - rspec_firefox
52
75
  rubygems-deploy:
53
76
  jobs:
54
77
  - deploy:
@@ -12,4 +12,4 @@ jobs:
12
12
  with:
13
13
  github_token: ${{ secrets.github_token }}
14
14
  reporter: github-pr-review
15
- rubocop_version: 0.86.0
15
+ rubocop_version: 0.90.0
@@ -35,6 +35,9 @@ Layout/EndAlignment:
35
35
  Layout/EmptyLineAfterMagicComment:
36
36
  Enabled: true
37
37
 
38
+ Layout/EmptyLineAfterMultilineCondition:
39
+ Enabled: true
40
+
38
41
  Layout/EmptyLinesAroundAccessModifier:
39
42
  Enabled: true
40
43
  EnforcedStyle: only_before
@@ -102,6 +105,10 @@ Layout/SpaceBeforeComment:
102
105
  Layout/SpaceBeforeFirstArg:
103
106
  Enabled: true
104
107
 
108
+ Style/ClassMethodsDefinitions:
109
+ Enabled: true
110
+ EnforcedStyle: def_self
111
+
105
112
  Style/DefWithParentheses:
106
113
  Enabled: true
107
114
 
@@ -109,9 +116,52 @@ Style/DefWithParentheses:
109
116
  Style/MethodDefParentheses:
110
117
  Enabled: true
111
118
 
119
+ Style/MethodCallWithArgsParentheses:
120
+ Enabled: true
121
+ IgnoredMethods:
122
+ # Gemfile, gemspec
123
+ - source
124
+ - add_dependency
125
+ - add_development_dependency
126
+
127
+ # include/require
128
+ - require
129
+ - require_relative
130
+ - include
131
+
132
+ # fundamental methods
133
+ - raise
134
+ - sleep
135
+
136
+ # RSpec
137
+ - describe
138
+ - it
139
+ - to
140
+ - not_to
141
+ - be
142
+ - eq
143
+
144
+ # async/await
145
+ - define_async_method
146
+ - await
147
+ - future
148
+
149
+ # utils
150
+ - debug_print
151
+ - debug_puts
152
+
153
+ Style/MethodCallWithoutArgsParentheses:
154
+ Enabled: true
155
+
112
156
  Style/RedundantFreeze:
113
157
  Enabled: true
114
158
 
159
+ Style/RedundantSelf:
160
+ Enabled: true
161
+
162
+ Style/RedundantSelfAssignment:
163
+ Enabled: true
164
+
115
165
  # Use `foo {}` not `foo{}`.
116
166
  Layout/SpaceBeforeBlockBraces:
117
167
  Enabled: true
@@ -164,9 +214,6 @@ Lint/EmptyConditionalBody:
164
214
  Lint/FloatComparison:
165
215
  Enabled: true
166
216
 
167
- Lint/MissingSuper:
168
- Enabled: true
169
-
170
217
  Lint/OutOfRangeRegexpRef:
171
218
  Enabled: true
172
219
 
@@ -0,0 +1,9 @@
1
+ FROM circleci/ruby:2.6.6-buster-node-browsers
2
+
3
+ USER root
4
+
5
+ RUN wget -O nightly.tar.bz2 "https://download.mozilla.org/?product=firefox-nightly-latest-ssl&os=linux64&lang=en-US" \
6
+ && tar xf nightly.tar.bz2 \
7
+ && ln -s $(pwd)/firefox/firefox /usr/bin/firefox
8
+
9
+ USER circleci
data/README.md CHANGED
@@ -47,8 +47,46 @@ Puppeteer.launch(headless: false, slow_mo: 50, args: ['--guest', '--window-size=
47
47
  end
48
48
  ```
49
49
 
50
+ ### Evaluate JavaScript
51
+
52
+ ```ruby
53
+ Puppeteer.launch do |browser|
54
+ page = browser.pages.last || browser.new_page
55
+ page.goto 'https://github.com/YusukeIwaki'
56
+
57
+ # Get the "viewport" of the page, as reported by the page.
58
+ dimensions = page.evaluate(<<~JAVASCRIPT)
59
+ () => {
60
+ return {
61
+ width: document.documentElement.clientWidth,
62
+ height: document.documentElement.clientHeight,
63
+ deviceScaleFactor: window.devicePixelRatio
64
+ };
65
+ }
66
+ JAVASCRIPT
67
+
68
+ puts "dimensions: #{dimensions}"
69
+ # => dimensions: {"width"=>800, "height"=>600, "deviceScaleFactor"=>1}
70
+ end
71
+ ```
72
+
50
73
  More usage examples can be found [here](https://github.com/YusukeIwaki/puppeteer-ruby-example)
51
74
 
75
+ ## :whale: Running in Docker
76
+
77
+ Following packages are required.
78
+
79
+ * Google Chrome or Chromium
80
+ * In Debian-based images, `google-chrome-stable`
81
+ * In Alpine-based images, `chromium`
82
+
83
+ Also, CJK font will be required for Chinese, Japanese, Korean sites.
84
+
85
+ ### References
86
+
87
+ * Puppeteer official README: https://github.com/puppeteer/puppeteer/blob/main/docs/troubleshooting.md#running-puppeteer-in-docker
88
+ * puppeteer-ruby example: https://github.com/YusukeIwaki/puppeteer-ruby-example/tree/master/docker_chromium
89
+
52
90
  ## :bulb: Collaboration with Selenium or Capybara
53
91
 
54
92
  It is really remarkable that we can use puppeteer functions in existing Selenium or Capybara codes, with a few configuration in advance.
@@ -0,0 +1,34 @@
1
+ version: "3"
2
+ services:
3
+ chrome:
4
+ tty: true
5
+ stdin_open: true
6
+ build: .
7
+ environment:
8
+ BUNDLE_PATH: /usr/local/bundle
9
+ DEBUG: 1
10
+ CI: 1
11
+ volumes:
12
+ - .:/puppeteer-ruby
13
+ - bundle-data:/usr/local/bundle
14
+ working_dir: /puppeteer-ruby
15
+ command: bundle exec rspec
16
+
17
+ firefox:
18
+ tty: true
19
+ stdin_open: true
20
+ build: .
21
+ environment:
22
+ BUNDLE_PATH: /usr/local/bundle
23
+ PUPPETEER_PRODUCT_RSPEC: firefox
24
+ DEBUG: 1
25
+ CI: 1
26
+ volumes:
27
+ - .:/puppeteer-ruby
28
+ - bundle-data:/usr/local/bundle
29
+ working_dir: /puppeteer-ruby
30
+ command: bundle exec rspec spec/integration/
31
+
32
+ volumes:
33
+ bundle-data:
34
+ driver: local
@@ -6,7 +6,9 @@ require 'puppeteer/env'
6
6
 
7
7
  # Custom data types.
8
8
  require 'puppeteer/device'
9
+ require 'puppeteer/events'
9
10
  require 'puppeteer/errors'
11
+ require 'puppeteer/geolocation'
10
12
  require 'puppeteer/viewport'
11
13
 
12
14
  # Modules
@@ -24,8 +26,10 @@ require 'puppeteer/cdp_session'
24
26
  require 'puppeteer/connection'
25
27
  require 'puppeteer/console_message'
26
28
  require 'puppeteer/devices'
29
+ require 'puppeteer/dialog'
27
30
  require 'puppeteer/dom_world'
28
31
  require 'puppeteer/emulation_manager'
32
+ require 'puppeteer/exception_details'
29
33
  require 'puppeteer/execution_context'
30
34
  require 'puppeteer/file_chooser'
31
35
  require 'puppeteer/frame'
@@ -53,17 +57,17 @@ require 'puppeteer/element_handle'
53
57
 
54
58
  # ref: https://github.com/puppeteer/puppeteer/blob/master/lib/Puppeteer.js
55
59
  class Puppeteer
56
- class << self
57
- def method_missing(method, *args, **kwargs, &block)
58
- instance.send(method, *args, **kwargs, &block)
59
- end
60
+ def self.method_missing(method, *args, **kwargs, &block)
61
+ @puppeteer ||= Puppeteer.new(
62
+ project_root: __dir__,
63
+ preferred_revision: '706915',
64
+ is_puppeteer_core: true,
65
+ )
60
66
 
61
- def instance
62
- @instance ||= Puppeteer.new(
63
- project_root: __dir__,
64
- preferred_revision: '706915',
65
- is_puppeteer_core: true,
66
- )
67
+ if kwargs.empty? # for Ruby < 2.7
68
+ @puppeteer.public_send(method, *args, &block)
69
+ else
70
+ @puppeteer.public_send(method, *args, **kwargs, &block)
67
71
  end
68
72
  end
69
73
 
@@ -130,7 +134,7 @@ class Puppeteer
130
134
  ignore_https_errors: ignore_https_errors,
131
135
  default_viewport: default_viewport,
132
136
  slow_mo: slow_mo,
133
- }.compact
137
+ }
134
138
 
135
139
  @product_name ||= product
136
140
  browser = launcher.launch(options)
@@ -46,37 +46,30 @@ class Puppeteer::Browser
46
46
  @contexts[context_id] = Puppeteer::BrowserContext.new(@connection, self, context_id)
47
47
  end
48
48
  @targets = {}
49
- @connection.on_event 'Events.Connection.Disconnected' do
50
- emit_event 'Events.Browser.Disconnected'
49
+ @connection.on_event(ConnectionEmittedEvents::Disconnected) do
50
+ emit_event(BrowserEmittedEvents::Disconnected)
51
51
  end
52
- @connection.on_event 'Target.targetCreated', &method(:handle_target_created)
53
- @connection.on_event 'Target.targetDestroyed', &method(:handle_target_destroyed)
54
- @connection.on_event 'Target.targetInfoChanged', &method(:handle_target_info_changed)
52
+ @connection.on_event('Target.targetCreated', &method(:handle_target_created))
53
+ @connection.on_event('Target.targetDestroyed', &method(:handle_target_destroyed))
54
+ @connection.on_event('Target.targetInfoChanged', &method(:handle_target_info_changed))
55
55
  end
56
56
 
57
- EVENT_MAPPINGS = {
58
- disconnected: 'Events.Browser.Disconnected',
59
- targetcreated: 'Events.Browser.TargetCreated',
60
- targetchanged: 'Events.Browser.TargetChanged',
61
- targetdestroyed: 'Events.Browser.TargetDestroyed',
62
- }
63
-
64
57
  # @param event_name [Symbol] either of :disconnected, :targetcreated, :targetchanged, :targetdestroyed
65
58
  def on(event_name, &block)
66
- unless EVENT_MAPPINGS.has_key?(event_name.to_sym)
67
- raise ArgumentError.new("Unknown event name: #{event_name}. Known events are #{EVENT_MAPPINGS.keys.join(", ")}")
59
+ unless BrowserEmittedEvents.values.include?(event_name.to_s)
60
+ raise ArgumentError.new("Unknown event name: #{event_name}. Known events are #{BrowserEmittedEvents.values.to_a.join(", ")}")
68
61
  end
69
62
 
70
- add_event_listener(EVENT_MAPPINGS[event_name.to_sym], &block)
63
+ super(event_name.to_s, &block)
71
64
  end
72
65
 
73
66
  # @param event_name [Symbol]
74
67
  def once(event_name, &block)
75
- unless EVENT_MAPPINGS.has_key?(event_name.to_sym)
76
- raise ArgumentError.new("Unknown event name: #{event_name}. Known events are #{EVENT_MAPPINGS.keys.join(", ")}")
68
+ unless BrowserEmittedEvents.values.include?(event_name.to_s)
69
+ raise ArgumentError.new("Unknown event name: #{event_name}. Known events are #{BrowserEmittedEvents.values.to_a.join(", ")}")
77
70
  end
78
71
 
79
- observe_first(EVENT_MAPPINGS[event_name.to_sym], &block)
72
+ super(event_name.to_s, &block)
80
73
  end
81
74
 
82
75
  # @return [Puppeteer::BrowserRunner::BrowserProcess]
@@ -137,8 +130,8 @@ class Puppeteer::Browser
137
130
  # assert(!this._targets.has(event.targetInfo.targetId), 'Target should not exist before targetCreated');
138
131
  @targets[target_info.target_id] = target
139
132
  if await target.initialized_promise
140
- emit_event 'Events.Browser.TargetCreated', target
141
- context.emit_event 'Events.BrowserContext.TargetCreated', target
133
+ emit_event(BrowserEmittedEvents::TargetCreated, target)
134
+ context.emit_event(BrowserContextEmittedEvents::TargetCreated, target)
142
135
  end
143
136
  end
144
137
 
@@ -150,8 +143,8 @@ class Puppeteer::Browser
150
143
  @targets.delete(target_id)
151
144
  target.closed_callback
152
145
  if await target.initialized_promise
153
- emit_event 'Events.Browser.TargetDestroyed', target
154
- target.browser_context.emit_event 'Events.BrowserContext.TargetDestroyed', target
146
+ emit_event(BrowserEmittedEvents::TargetDestroyed, target)
147
+ target.browser_context.emit_event(BrowserContextEmittedEvents::TargetDestroyed, target)
155
148
  end
156
149
  end
157
150
 
@@ -169,8 +162,8 @@ class Puppeteer::Browser
169
162
  was_initialized = target.initialized?
170
163
  target.handle_target_info_changed(target_info)
171
164
  if was_initialized && previous_url != target.url
172
- emit_event 'Events.Browser.TargetChanged', target
173
- target.browser_context.emit_event 'Events.BrowserContext.TargetChanged', target
165
+ emit_event(BrowserEmittedEvents::TargetChanged, target)
166
+ target.browser_context.emit_event(BrowserContextEmittedEvents::TargetChanged, target)
174
167
  end
175
168
  end
176
169
 
@@ -222,12 +215,12 @@ class Puppeteer::Browser
222
215
 
223
216
  event_listening_ids = []
224
217
  target_promise = resolvable_future
225
- event_listening_ids << add_event_listener('Events.Browser.TargetCreated') do |target|
218
+ event_listening_ids << add_event_listener(BrowserEmittedEvents::TargetCreated) do |target|
226
219
  if predicate.call(target)
227
220
  target_promise.fulfill(target)
228
221
  end
229
222
  end
230
- event_listening_ids << add_event_listener('Events.Browser.TargetChanged') do |target|
223
+ event_listening_ids << add_event_listener(BrowserEmittedEvents::TargetChanged) do |target|
231
224
  if predicate.call(target)
232
225
  target_promise.fulfill(target)
233
226
  end
@@ -11,29 +11,22 @@ class Puppeteer::BrowserContext
11
11
  @id = context_id
12
12
  end
13
13
 
14
- EVENT_MAPPINGS = {
15
- disconnected: 'Events.BrowserContext.Disconnected',
16
- targetcreated: 'Events.BrowserContext.TargetCreated',
17
- targetchanged: 'Events.BrowserContext.TargetChanged',
18
- targetdestroyed: 'Events.BrowserContext.TargetDestroyed',
19
- }
20
-
21
14
  # @param event_name [Symbol] either of :disconnected, :targetcreated, :targetchanged, :targetdestroyed
22
15
  def on(event_name, &block)
23
- unless EVENT_MAPPINGS.has_key?(event_name.to_sym)
24
- raise ArgumentError.new("Unknown event name: #{event_name}. Known events are #{EVENT_MAPPINGS.keys.join(", ")}")
16
+ unless BrowserContextEmittedEvents.values.include?(event_name.to_s)
17
+ raise ArgumentError.new("Unknown event name: #{event_name}. Known events are #{BrowserContextEmittedEvents.values.to_a.join(", ")}")
25
18
  end
26
19
 
27
- add_event_listener(EVENT_MAPPINGS[event_name.to_sym], &block)
20
+ super(event_name.to_s, &block)
28
21
  end
29
22
 
30
23
  # @param event_name [Symbol]
31
24
  def once(event_name, &block)
32
- unless EVENT_MAPPINGS.has_key?(event_name.to_sym)
33
- raise ArgumentError.new("Unknown event name: #{event_name}. Known events are #{EVENT_MAPPINGS.keys.join(", ")}")
25
+ unless BrowserContextEmittedEvents.values.include?(event_name.to_s)
26
+ raise ArgumentError.new("Unknown event name: #{event_name}. Known events are #{BrowserContextEmittedEvents.values.to_a.join(", ")}")
34
27
  end
35
28
 
36
- observe_first(EVENT_MAPPINGS[event_name.to_sym], &block)
29
+ super(event_name.to_s, &block)
37
30
  end
38
31
 
39
32
  # @return {!Array<!Target>} target
@@ -64,42 +57,48 @@ class Puppeteer::BrowserContext
64
57
  !!@id
65
58
  end
66
59
 
67
- # /**
68
- # * @param {string} origin
69
- # * @param {!Array<string>} permissions
70
- # */
71
- # async overridePermissions(origin, permissions) {
72
- # const webPermissionToProtocol = new Map([
73
- # ['geolocation', 'geolocation'],
74
- # ['midi', 'midi'],
75
- # ['notifications', 'notifications'],
76
- # ['push', 'push'],
77
- # ['camera', 'videoCapture'],
78
- # ['microphone', 'audioCapture'],
79
- # ['background-sync', 'backgroundSync'],
80
- # ['ambient-light-sensor', 'sensors'],
81
- # ['accelerometer', 'sensors'],
82
- # ['gyroscope', 'sensors'],
83
- # ['magnetometer', 'sensors'],
84
- # ['accessibility-events', 'accessibilityEvents'],
85
- # ['clipboard-read', 'clipboardRead'],
86
- # ['clipboard-write', 'clipboardWrite'],
87
- # ['payment-handler', 'paymentHandler'],
88
- # // chrome-specific permissions we have.
89
- # ['midi-sysex', 'midiSysex'],
90
- # ]);
91
- # permissions = permissions.map(permission => {
92
- # const protocolPermission = webPermissionToProtocol.get(permission);
93
- # if (!protocolPermission)
94
- # throw new Error('Unknown permission: ' + permission);
95
- # return protocolPermission;
96
- # });
97
- # await this._connection.send('Browser.grantPermissions', {origin, browserContextId: this._id || undefined, permissions});
98
- # }
99
-
100
- # async clearPermissionOverrides() {
101
- # await this._connection.send('Browser.resetPermissions', {browserContextId: this._id || undefined});
102
- # }
60
+ WEB_PERMISSION_TO_PROTOCOL = {
61
+ 'geolocation' => 'geolocation',
62
+ 'midi' => 'midi',
63
+ 'notifications' => 'notifications',
64
+ # TODO: push isn't a valid type?
65
+ # 'push' => 'push',
66
+ 'camera' => 'videoCapture',
67
+ 'microphone' => 'audioCapture',
68
+ 'background-sync' => 'backgroundSync',
69
+ 'ambient-light-sensor' => 'sensors',
70
+ 'accelerometer' => 'sensors',
71
+ 'gyroscope' => 'sensors',
72
+ 'magnetometer' => 'sensors',
73
+ 'accessibility-events' => 'accessibilityEvents',
74
+ 'clipboard-read' => 'clipboardReadWrite',
75
+ 'clipboard-write' => 'clipboardReadWrite',
76
+ 'payment-handler' => 'paymentHandler',
77
+ 'idle-detection' => 'idleDetection',
78
+ # chrome-specific permissions we have.
79
+ 'midi-sysex' => 'midiSysex',
80
+ }.freeze
81
+
82
+ # @param origin [String]
83
+ # @param permissions [Array<String>]
84
+ def override_permissions(origin, permissions)
85
+ protocol_permissions = permissions.map do |permission|
86
+ WEB_PERMISSION_TO_PROTOCOL[permission] or raise ArgumentError.new("Unknown permission: #{permission}")
87
+ end
88
+ @connection.send_message('Browser.grantPermissions', {
89
+ origin: origin,
90
+ browserContextId: @id,
91
+ permissions: protocol_permissions,
92
+ }.compact)
93
+ end
94
+
95
+ def clear_permission_overrides
96
+ if @id
97
+ @connection.send_message('Browser.resetPermissions', browserContextId: @id)
98
+ else
99
+ @connection.send_message('Browser.resetPermissions')
100
+ end
101
+ end
103
102
 
104
103
  # @return [Future<Puppeteer::Page>]
105
104
  def new_page