apparition 0.1.0 → 0.6.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (35) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +40 -4
  3. data/lib/capybara/apparition.rb +0 -2
  4. data/lib/capybara/apparition/browser.rb +75 -133
  5. data/lib/capybara/apparition/browser/cookie.rb +4 -16
  6. data/lib/capybara/apparition/browser/header.rb +2 -2
  7. data/lib/capybara/apparition/browser/launcher.rb +25 -0
  8. data/lib/capybara/apparition/browser/launcher/local.rb +213 -0
  9. data/lib/capybara/apparition/browser/launcher/remote.rb +55 -0
  10. data/lib/capybara/apparition/browser/page_manager.rb +90 -0
  11. data/lib/capybara/apparition/browser/window.rb +29 -29
  12. data/lib/capybara/apparition/configuration.rb +100 -0
  13. data/lib/capybara/apparition/console.rb +8 -1
  14. data/lib/capybara/apparition/dev_tools_protocol/remote_object.rb +23 -7
  15. data/lib/capybara/apparition/dev_tools_protocol/session.rb +3 -4
  16. data/lib/capybara/apparition/driver.rb +107 -35
  17. data/lib/capybara/apparition/driver/chrome_client.rb +13 -8
  18. data/lib/capybara/apparition/driver/response.rb +1 -1
  19. data/lib/capybara/apparition/driver/web_socket_client.rb +1 -0
  20. data/lib/capybara/apparition/errors.rb +3 -3
  21. data/lib/capybara/apparition/network_traffic/error.rb +1 -0
  22. data/lib/capybara/apparition/network_traffic/request.rb +5 -5
  23. data/lib/capybara/apparition/node.rb +142 -50
  24. data/lib/capybara/apparition/node/drag.rb +165 -65
  25. data/lib/capybara/apparition/page.rb +180 -142
  26. data/lib/capybara/apparition/page/frame.rb +3 -0
  27. data/lib/capybara/apparition/page/frame_manager.rb +2 -1
  28. data/lib/capybara/apparition/page/keyboard.rb +29 -7
  29. data/lib/capybara/apparition/page/mouse.rb +20 -6
  30. data/lib/capybara/apparition/utility.rb +1 -1
  31. data/lib/capybara/apparition/version.rb +1 -1
  32. metadata +53 -23
  33. data/lib/capybara/apparition/dev_tools_protocol/target.rb +0 -64
  34. data/lib/capybara/apparition/dev_tools_protocol/target_manager.rb +0 -48
  35. data/lib/capybara/apparition/driver/launcher.rb +0 -217
@@ -47,10 +47,12 @@ module Capybara::Apparition
47
47
  end
48
48
 
49
49
  def loading(id)
50
+ puts "Setting loading to #{id}" if ENV['DEBUG']
50
51
  self.loader_id = id
51
52
  end
52
53
 
53
54
  def reloading!
55
+ puts 'Reloading' if ENV['DEBUG']
54
56
  self.loader_id = @prev_loader_id
55
57
  end
56
58
 
@@ -64,6 +66,7 @@ module Capybara::Apparition
64
66
 
65
67
  def loaded!
66
68
  @prev_loader_id = loader_id
69
+ puts "Setting loaded - was #{loader_id}" if ENV['DEBUG']
67
70
  self.loader_id = nil
68
71
  end
69
72
 
@@ -7,7 +7,7 @@ module Capybara::Apparition
7
7
  def initialize(id)
8
8
  @frames = {}
9
9
  @frames_mutex = Mutex.new
10
- add(id)
10
+ add(id).loading(-1)
11
11
  @main_id = @current_id = id
12
12
  end
13
13
 
@@ -43,6 +43,7 @@ module Capybara::Apparition
43
43
  @frames[id]
44
44
  end
45
45
  end
46
+ alias :[] :get
46
47
 
47
48
  def delete(id)
48
49
  @frames_mutex.synchronize do
@@ -66,16 +66,30 @@ module Capybara::Apparition
66
66
 
67
67
  private
68
68
 
69
+ def insert_emoji(str)
70
+ @page.command('Input.insertText', text: str)
71
+ end
72
+
69
73
  def type_with_modifiers(keys, delay:)
70
74
  old_pressed_keys, @pressed_keys = @pressed_keys, {}
71
75
 
72
76
  Array(keys).each do |sequence|
73
77
  case sequence
74
- when Array then type_with_modifiers(sequence, delay: delay)
75
- when String then sequence.each_char do |char|
76
- press char
77
- sleep delay
78
- end
78
+ when Array
79
+ type_with_modifiers(sequence, delay: delay)
80
+ when String
81
+ clusters = sequence.grapheme_clusters.chunk { |gc| gc.match?(/\p{Emoji Presentation}/) }
82
+ clusters.each do |emoji, chars|
83
+ if emoji
84
+ insert_emoji(chars.join)
85
+ sleep delay
86
+ else
87
+ chars.each do |char|
88
+ press char
89
+ sleep delay
90
+ end
91
+ end
92
+ end
79
93
  else
80
94
  press sequence
81
95
  sleep delay
@@ -89,7 +103,7 @@ module Capybara::Apparition
89
103
  end
90
104
 
91
105
  def release_pressed_keys
92
- @pressed_keys.values.each { |desc| up(desc) }
106
+ @pressed_keys.each_value { |desc| up(desc) }
93
107
  end
94
108
 
95
109
  def key_description(key)
@@ -102,8 +116,15 @@ module Capybara::Apparition
102
116
  location: 0
103
117
  )
104
118
 
119
+ if key.to_sym == :return
120
+ warn '[DEPRECATION]: Key symbol :return is deprecated in favor of :enter'
121
+ key = :enter
122
+ end
123
+
105
124
  definition = KEY_DEFINITIONS[key.to_sym]
106
- raise KeyError, "Unknown key: #{key}" if definition.nil?
125
+ raise KeyError, "Unknown key: #{key}" if definition.nil? && !key.is_a?(String)
126
+
127
+ definition ||= { text: key }
107
128
 
108
129
  definition = OpenStruct.new definition
109
130
 
@@ -321,6 +342,7 @@ module Capybara::Apparition
321
342
  'z': { 'keyCode': 90, 'code': 'KeyZ', 'shiftKey': 'Z', 'key': 'z' },
322
343
  'meta': { 'keyCode': 91, 'key': 'Meta', 'code': 'MetaLeft' },
323
344
  'command': { 'keyCode': 91, 'key': 'Meta', 'code': 'MetaLeft' },
345
+ 'cmd': { 'keyCode': 91, 'key': 'Meta', 'code': 'MetaLeft' },
324
346
  '*': { 'keyCode': 106, 'key': '*', 'code': 'NumpadMultiply', 'location': 3 },
325
347
  '+': { 'keyCode': 107, 'key': '+', 'code': 'NumpadAdd', 'location': 3 },
326
348
  '-': { 'keyCode': 109, 'key': '-', 'code': 'NumpadSubtract', 'location': 3 },
@@ -6,15 +6,17 @@ module Capybara::Apparition
6
6
  @page = page
7
7
  @keyboard = keyboard
8
8
  @current_pos = { x: 0, y: 0 }
9
+ @current_buttons = BUTTONS[:none]
9
10
  end
10
11
 
11
- def click_at(x:, y:, button: 'left', count: 1, modifiers: [])
12
+ def click_at(x:, y:, button: 'left', count: 1, delay: 0, modifiers: [])
12
13
  move_to x: x, y: y
13
14
  count.times do |num|
14
15
  @keyboard.with_keys(modifiers) do
15
16
  mouse_params = { x: x, y: y, button: button, count: num + 1 }
16
- down mouse_params
17
- up mouse_params
17
+ down(**mouse_params)
18
+ sleep(delay || 0)
19
+ up(**mouse_params)
18
20
  end
19
21
  end
20
22
  self
@@ -28,13 +30,15 @@ module Capybara::Apparition
28
30
 
29
31
  def down(button: 'left', **options)
30
32
  options = @current_pos.merge(button: button).merge(options)
31
- mouse_event('mousePressed', options)
33
+ mouse_event('mousePressed', **options)
34
+ @current_buttons |= BUTTONS[button.to_sym]
32
35
  self
33
36
  end
34
37
 
35
38
  def up(button: 'left', **options)
36
39
  options = @current_pos.merge(button: button).merge(options)
37
- mouse_event('mouseReleased', options)
40
+ @current_buttons &= ~BUTTONS[button.to_sym]
41
+ mouse_event('mouseReleased', **options)
38
42
  self
39
43
  end
40
44
 
@@ -43,11 +47,21 @@ module Capybara::Apparition
43
47
  def mouse_event(type, x:, y:, button: 'none', count: 1)
44
48
  @page.command('Input.dispatchMouseEvent',
45
49
  type: type,
46
- button: button,
50
+ button: button.to_s,
51
+ buttons: @current_buttons,
47
52
  x: x,
48
53
  y: y,
49
54
  modifiers: @keyboard.modifiers,
50
55
  clickCount: count)
51
56
  end
57
+
58
+ BUTTONS = {
59
+ left: 1,
60
+ right: 2,
61
+ middle: 4,
62
+ back: 8,
63
+ forward: 16,
64
+ none: 0
65
+ }.freeze
52
66
  end
53
67
  end
@@ -4,7 +4,7 @@ module Capybara
4
4
  module Apparition
5
5
  class << self
6
6
  def windows?
7
- RbConfig::CONFIG['host_os'] =~ /mingw|mswin|cygwin/
7
+ RbConfig::CONFIG['host_os'].match?(/mingw|mswin|cygwin/)
8
8
  end
9
9
 
10
10
  def mri?
@@ -2,6 +2,6 @@
2
2
 
3
3
  module Capybara
4
4
  module Apparition
5
- VERSION = '0.1.0'
5
+ VERSION = '0.6.0'
6
6
  end
7
7
  end
metadata CHANGED
@@ -1,36 +1,22 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: apparition
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.6.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Thomas Walpole
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2019-02-05 00:00:00.000000000 Z
11
+ date: 2020-06-21 00:00:00.000000000 Z
12
12
  dependencies:
13
- - !ruby/object:Gem::Dependency
14
- name: backports
15
- requirement: !ruby/object:Gem::Requirement
16
- requirements:
17
- - - ">="
18
- - !ruby/object:Gem::Version
19
- version: '0'
20
- type: :runtime
21
- prerelease: false
22
- version_requirements: !ruby/object:Gem::Requirement
23
- requirements:
24
- - - ">="
25
- - !ruby/object:Gem::Version
26
- version: '0'
27
13
  - !ruby/object:Gem::Dependency
28
14
  name: capybara
29
15
  requirement: !ruby/object:Gem::Requirement
30
16
  requirements:
31
17
  - - "~>"
32
18
  - !ruby/object:Gem::Version
33
- version: '3.12'
19
+ version: '3.13'
34
20
  - - "<"
35
21
  - !ruby/object:Gem::Version
36
22
  version: '4'
@@ -40,7 +26,7 @@ dependencies:
40
26
  requirements:
41
27
  - - "~>"
42
28
  - !ruby/object:Gem::Version
43
- version: '3.12'
29
+ version: '3.13'
44
30
  - - "<"
45
31
  - !ruby/object:Gem::Version
46
32
  version: '4'
@@ -184,6 +170,48 @@ dependencies:
184
170
  - - "~>"
185
171
  - !ruby/object:Gem::Version
186
172
  version: '3.6'
173
+ - !ruby/object:Gem::Dependency
174
+ name: rubocop
175
+ requirement: !ruby/object:Gem::Requirement
176
+ requirements:
177
+ - - ">="
178
+ - !ruby/object:Gem::Version
179
+ version: '0'
180
+ type: :development
181
+ prerelease: false
182
+ version_requirements: !ruby/object:Gem::Requirement
183
+ requirements:
184
+ - - ">="
185
+ - !ruby/object:Gem::Version
186
+ version: '0'
187
+ - !ruby/object:Gem::Dependency
188
+ name: rubocop-performance
189
+ requirement: !ruby/object:Gem::Requirement
190
+ requirements:
191
+ - - ">="
192
+ - !ruby/object:Gem::Version
193
+ version: '0'
194
+ type: :development
195
+ prerelease: false
196
+ version_requirements: !ruby/object:Gem::Requirement
197
+ requirements:
198
+ - - ">="
199
+ - !ruby/object:Gem::Version
200
+ version: '0'
201
+ - !ruby/object:Gem::Dependency
202
+ name: rubocop-rspec
203
+ requirement: !ruby/object:Gem::Requirement
204
+ requirements:
205
+ - - ">="
206
+ - !ruby/object:Gem::Version
207
+ version: '0'
208
+ type: :development
209
+ prerelease: false
210
+ version_requirements: !ruby/object:Gem::Requirement
211
+ requirements:
212
+ - - ">="
213
+ - !ruby/object:Gem::Version
214
+ version: '0'
187
215
  - !ruby/object:Gem::Dependency
188
216
  name: selenium-webdriver
189
217
  requirement: !ruby/object:Gem::Requirement
@@ -228,19 +256,21 @@ files:
228
256
  - lib/capybara/apparition/browser/cookie.rb
229
257
  - lib/capybara/apparition/browser/frame.rb
230
258
  - lib/capybara/apparition/browser/header.rb
259
+ - lib/capybara/apparition/browser/launcher.rb
260
+ - lib/capybara/apparition/browser/launcher/local.rb
261
+ - lib/capybara/apparition/browser/launcher/remote.rb
231
262
  - lib/capybara/apparition/browser/modal.rb
263
+ - lib/capybara/apparition/browser/page_manager.rb
232
264
  - lib/capybara/apparition/browser/render.rb
233
265
  - lib/capybara/apparition/browser/window.rb
266
+ - lib/capybara/apparition/configuration.rb
234
267
  - lib/capybara/apparition/console.rb
235
268
  - lib/capybara/apparition/cookie.rb
236
269
  - lib/capybara/apparition/cookie_jar.rb
237
270
  - lib/capybara/apparition/dev_tools_protocol/remote_object.rb
238
271
  - lib/capybara/apparition/dev_tools_protocol/session.rb
239
- - lib/capybara/apparition/dev_tools_protocol/target.rb
240
- - lib/capybara/apparition/dev_tools_protocol/target_manager.rb
241
272
  - lib/capybara/apparition/driver.rb
242
273
  - lib/capybara/apparition/driver/chrome_client.rb
243
- - lib/capybara/apparition/driver/launcher.rb
244
274
  - lib/capybara/apparition/driver/response.rb
245
275
  - lib/capybara/apparition/driver/web_socket_client.rb
246
276
  - lib/capybara/apparition/errors.rb
@@ -270,14 +300,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
270
300
  requirements:
271
301
  - - ">="
272
302
  - !ruby/object:Gem::Version
273
- version: 2.3.0
303
+ version: 2.5.0
274
304
  required_rubygems_version: !ruby/object:Gem::Requirement
275
305
  requirements:
276
306
  - - ">="
277
307
  - !ruby/object:Gem::Version
278
308
  version: '0'
279
309
  requirements: []
280
- rubygems_version: 3.0.1
310
+ rubygems_version: 3.1.2
281
311
  signing_key:
282
312
  specification_version: 4
283
313
  summary: Chrome driver using CDP for Capybara
@@ -1,64 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require 'capybara/apparition/dev_tools_protocol/session'
4
-
5
- module Capybara::Apparition
6
- module DevToolsProtocol
7
- class Target
8
- def initialize(browser, info)
9
- @browser = browser
10
- @info = info.dup
11
- @page = nil
12
- end
13
-
14
- def info
15
- @info.dup.freeze
16
- end
17
-
18
- def update(new_info)
19
- @info ||= {}
20
- @info.merge!(new_info)
21
- info
22
- end
23
-
24
- def id
25
- @info['targetId']
26
- end
27
-
28
- def context_id
29
- @info['browserContextId']
30
- end
31
-
32
- def title
33
- @info['title']
34
- end
35
-
36
- def url
37
- @info['url']
38
- end
39
-
40
- def page
41
- @page ||= begin
42
- if info['type'] == 'page'
43
- Page.create(@browser, create_session, id,
44
- ignore_https_errors: @browser.ignore_https_errors,
45
- js_errors: @browser.js_errors).inherit(@info.delete('inherit'))
46
- else
47
- nil
48
- end
49
- end
50
- end
51
-
52
- def close
53
- @browser.command('Target.closeTarget', targetId: id)
54
- end
55
-
56
- private
57
-
58
- def create_session
59
- session_id = @browser.command('Target.attachToTarget', targetId: id)['sessionId']
60
- Session.new(@browser, @browser.client, id, session_id)
61
- end
62
- end
63
- end
64
- end
@@ -1,48 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require 'capybara/apparition/dev_tools_protocol/target'
4
-
5
- module Capybara::Apparition
6
- module DevToolsProtocol
7
- class TargetManager
8
- def initialize(browser)
9
- @browser = browser
10
- @targets = {}
11
- end
12
-
13
- def get(id)
14
- @targets[id]
15
- end
16
-
17
- def of_type(type)
18
- @targets.select { |_id, target| target.info['type'] == type }
19
- end
20
-
21
- def add(id, target)
22
- raise ArgumentError, 'Target already exists' if @targets.key?(id)
23
-
24
- @targets[id] = if target.is_a? DevToolsProtocol::Target
25
- target
26
- else
27
- DevToolsProtocol::Target.new(@browser, target)
28
- end
29
- end
30
-
31
- def delete(id)
32
- @targets.delete(id)
33
- end
34
-
35
- def pages
36
- @targets.values.select { |target| target.info['type'] == 'page' }.map(&:page)
37
- end
38
-
39
- def target?(id)
40
- @targets.key?(id)
41
- end
42
-
43
- def window_handles
44
- @targets.values.select { |target| target.info['type'] == 'page' }.map(&:id).compact
45
- end
46
- end
47
- end
48
- end
@@ -1,217 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Capybara::Apparition
4
- class Browser
5
- class Launcher
6
- KILL_TIMEOUT = 2
7
-
8
- def self.start(*args)
9
- new(*args).tap(&:start)
10
- end
11
-
12
- def self.process_killer(pid)
13
- proc do
14
- begin
15
- if Capybara::Apparition.windows?
16
- ::Process.kill('KILL', pid)
17
- else
18
- ::Process.kill('TERM', pid)
19
- timer = Capybara::Helpers.timer(expire_in: KILL_TIMEOUT)
20
- while ::Process.wait(pid, ::Process::WNOHANG).nil?
21
- sleep 0.05
22
- next unless timer.expired?
23
-
24
- ::Process.kill('KILL', pid)
25
- ::Process.wait(pid)
26
- break
27
- end
28
- end
29
- rescue Errno::ESRCH, Errno::ECHILD # rubocop:disable Lint/HandleExceptions
30
- end
31
- end
32
- end
33
-
34
- def initialize(headless:, **options)
35
- @path = ENV['BROWSER_PATH']
36
- @options = DEFAULT_OPTIONS.merge(options[:browser_options] || {})
37
- if headless
38
- @options.merge!(HEADLESS_OPTIONS)
39
- @options['disable-gpu'] = nil if Capybara::Apparition.windows?
40
- end
41
- @options['user-data-dir'] = Dir.mktmpdir
42
- end
43
-
44
- def start
45
- @output = Queue.new
46
- @read_io, @write_io = IO.pipe
47
-
48
- @out_thread = Thread.new do
49
- while !@read_io.eof? && (data = @read_io.readpartial(512))
50
- @output << data
51
- end
52
- end
53
-
54
- process_options = { in: File::NULL }
55
- process_options[:pgroup] = true unless Capybara::Apparition.windows?
56
- process_options[:out] = process_options[:err] = @write_io if Capybara::Apparition.mri?
57
-
58
- redirect_stdout do
59
- cmd = [path] + @options.map { |k, v| v.nil? ? "--#{k}" : "--#{k}=#{v}" }
60
- @pid = ::Process.spawn(*cmd, process_options)
61
- ObjectSpace.define_finalizer(self, self.class.process_killer(@pid))
62
- end
63
- end
64
-
65
- def stop
66
- return unless @pid
67
-
68
- kill
69
- ObjectSpace.undefine_finalizer(self)
70
- end
71
-
72
- def restart
73
- stop
74
- start
75
- end
76
-
77
- def host
78
- @host ||= ws_url.host
79
- end
80
-
81
- def port
82
- @port ||= ws_url.port
83
- end
84
-
85
- def ws_url
86
- @ws_url ||= begin
87
- regexp = %r{DevTools listening on (ws://.*)}
88
- url = nil
89
- loop do
90
- break if (url = @output.pop.scan(regexp)[0])
91
- end
92
- @out_thread.kill
93
- close_io
94
- Addressable::URI.parse(url[0])
95
- end
96
- end
97
-
98
- private
99
-
100
- def redirect_stdout
101
- if Capybara::Apparition.mri?
102
- yield
103
- else
104
- begin
105
- prev = STDOUT.dup
106
- $stdout = @write_io
107
- STDOUT.reopen(@write_io)
108
- yield
109
- ensure
110
- STDOUT.reopen(prev)
111
- $stdout = STDOUT
112
- prev.close
113
- end
114
- end
115
- end
116
-
117
- def kill
118
- self.class.process_killer(@pid).call
119
- @pid = nil
120
- end
121
-
122
- def close_io
123
- [@write_io, @read_io].each do |io|
124
- begin
125
- io.close unless io.closed?
126
- rescue IOError
127
- raise unless RUBY_ENGINE == 'jruby'
128
- end
129
- end
130
- end
131
-
132
- def path
133
- host_os = RbConfig::CONFIG['host_os']
134
- @path ||= case RbConfig::CONFIG['host_os']
135
- when /mswin|msys|mingw|cygwin|bccwin|wince|emc/
136
- windows_path
137
- when /darwin|mac os/
138
- macosx_path
139
- when /linux|solaris|bsd/
140
- find_first_binary('google-chrome', 'chrome') || '/usr/bin/chrome'
141
- else
142
- raise ArgumentError, "unknown os: #{host_os.inspect}"
143
- end
144
-
145
- raise ArgumentError, 'Unable to find Chrome executeable' unless File.file?(@path.to_s) && File.executable?(@path.to_s)
146
-
147
- @path
148
- end
149
-
150
- def windows_path
151
- raise ArgumentError, 'Not yet Implemented'
152
- end
153
-
154
- def macosx_path
155
- path = '/Applications/Google Chrome.app/Contents/MacOS/Google Chrome'
156
- path = File.expand_path("~#{path}") unless File.exist?(path)
157
- path = find_first_binary('Google Chrome') unless File.exist?(path)
158
- path
159
- end
160
-
161
- def find_first_binary(*binaries)
162
- paths = ENV['PATH'].split(File::PATH_SEPARATOR)
163
-
164
- binaries.each do |binary|
165
- paths.each do |path|
166
- full_path = File.join(path, binary)
167
- exe = Dir.glob(full_path).find { |f| File.executable?(f) }
168
- return exe if exe
169
- end
170
- end
171
- end
172
-
173
- # Chromium command line options
174
- # https://peter.sh/experiments/chromium-command-line-switches/
175
- DEFAULT_BOOLEAN_OPTIONS = %w[
176
- disable-background-networking
177
- disable-background-timer-throttling
178
- disable-breakpad
179
- disable-client-side-phishing-detection
180
- disable-default-apps
181
- disable-dev-shm-usage
182
- disable-extensions
183
- disable-features=site-per-process
184
- disable-hang-monitor
185
- disable-infobars
186
- disable-popup-blocking
187
- disable-prompt-on-repost
188
- disable-sync
189
- disable-translate
190
- metrics-recording-only
191
- no-first-run
192
- safebrowsing-disable-auto-update
193
- enable-automation
194
- password-store=basic
195
- use-mock-keychain
196
- keep-alive-for-test
197
- ].freeze
198
- # Note: --no-sandbox is not needed if you properly setup a user in the container.
199
- # https://github.com/ebidel/lighthouse-ci/blob/master/builder/Dockerfile#L35-L40
200
- # no-sandbox
201
- # disable-web-security
202
- DEFAULT_VALUE_OPTIONS = {
203
- 'window-size' => '1024,768',
204
- 'homepage' => 'about:blank',
205
- 'remote-debugging-address' => '127.0.0.1'
206
- }.freeze
207
- DEFAULT_OPTIONS = DEFAULT_BOOLEAN_OPTIONS.each_with_object({}) { |opt, hsh| hsh[opt] = nil }
208
- .merge(DEFAULT_VALUE_OPTIONS)
209
- .freeze
210
- HEADLESS_OPTIONS = {
211
- 'headless' => nil,
212
- 'hide-scrollbars' => nil,
213
- 'mute-audio' => nil
214
- }.freeze
215
- end
216
- end
217
- end