puppeteer-ruby 0.0.14 → 0.0.19
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.
- checksums.yaml +4 -4
- data/.circleci/config.yml +25 -2
- data/.github/workflows/reviewdog.yml +1 -1
- data/.rubocop.yml +49 -3
- data/Dockerfile +9 -0
- data/README.md +3 -1
- data/docker-compose.yml +34 -0
- data/lib/puppeteer.rb +16 -12
- data/lib/puppeteer/browser.rb +36 -9
- data/lib/puppeteer/browser_context.rb +35 -5
- data/lib/puppeteer/browser_runner.rb +1 -1
- data/lib/puppeteer/connection.rb +6 -1
- data/lib/puppeteer/debug_print.rb +2 -2
- data/lib/puppeteer/define_async_method.rb +1 -1
- data/lib/puppeteer/dom_world.rb +78 -52
- data/lib/puppeteer/element_handle.rb +49 -20
- data/lib/puppeteer/env.rb +23 -0
- data/lib/puppeteer/frame.rb +17 -31
- data/lib/puppeteer/js_handle.rb +37 -27
- data/lib/puppeteer/keyboard.rb +3 -2
- data/lib/puppeteer/launcher.rb +11 -1
- data/lib/puppeteer/launcher/base.rb +14 -4
- data/lib/puppeteer/launcher/chrome.rb +1 -1
- data/lib/puppeteer/launcher/firefox.rb +392 -0
- data/lib/puppeteer/mouse.rb +16 -0
- data/lib/puppeteer/network_manager.rb +163 -5
- data/lib/puppeteer/page.rb +195 -125
- data/lib/puppeteer/page/pdf_options.rb +166 -0
- data/lib/puppeteer/remote_object.rb +28 -1
- data/lib/puppeteer/request.rb +330 -0
- data/lib/puppeteer/response.rb +113 -0
- data/lib/puppeteer/version.rb +1 -1
- data/lib/puppeteer/wait_task.rb +1 -1
- data/lib/puppeteer/web_socket.rb +7 -0
- data/puppeteer-ruby.gemspec +2 -1
- metadata +25 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 6e6a29713aa4dd143bdd6c4fd1cc84df1bd7037aa920b0d660a62267f6321515
|
4
|
+
data.tar.gz: 46a433d484dfabd019cc0874b8dd6c17182e374fb53d6f6905fde7c1d120d5e6
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 9c5796c2331a9218c1191e1c2869aa5b02c6affdd19f5af23324ee1b257e93d3f328688b19ac14b4060f050c3649a82f6074f0a2b5d66c4bb71f34f46d51557a
|
7
|
+
data.tar.gz: 70bfa15d8c788ab11dbf8cf240a3967a906a15777294b1f8be2be22a64d5f2123a3c4bf44226c35c58bed0614a9b7703d6db498ce283309aa36bb30c5587cea6
|
data/.circleci/config.yml
CHANGED
@@ -5,7 +5,7 @@ orbs:
|
|
5
5
|
jobs:
|
6
6
|
rspec:
|
7
7
|
docker:
|
8
|
-
- image: circleci/ruby:2.6.
|
8
|
+
- image: circleci/ruby:2.6.6-buster-node-browsers
|
9
9
|
executor: ruby/default
|
10
10
|
steps:
|
11
11
|
- checkout
|
@@ -13,10 +13,32 @@ jobs:
|
|
13
13
|
- run:
|
14
14
|
name: rspec
|
15
15
|
command: |
|
16
|
+
DEBUG=1 bundle exec rspec --profile 10 \
|
17
|
+
--format RspecJunitFormatter \
|
18
|
+
--out test_results/rspec.xml \
|
19
|
+
--format documentation
|
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 \
|
16
38
|
bundle exec rspec --profile 10 \
|
17
39
|
--format RspecJunitFormatter \
|
18
40
|
--out test_results/rspec.xml \
|
19
|
-
--format
|
41
|
+
--format documentation spec/integration/
|
20
42
|
|
21
43
|
deploy:
|
22
44
|
docker:
|
@@ -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:
|
data/.rubocop.yml
CHANGED
@@ -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
|
|
@@ -112,6 +119,12 @@ Style/MethodDefParentheses:
|
|
112
119
|
Style/RedundantFreeze:
|
113
120
|
Enabled: true
|
114
121
|
|
122
|
+
Style/RedundantSelf:
|
123
|
+
Enabled: true
|
124
|
+
|
125
|
+
Style/RedundantSelfAssignment:
|
126
|
+
Enabled: true
|
127
|
+
|
115
128
|
# Use `foo {}` not `foo{}`.
|
116
129
|
Layout/SpaceBeforeBlockBraces:
|
117
130
|
Enabled: true
|
@@ -146,17 +159,44 @@ Lint/AmbiguousOperator:
|
|
146
159
|
Lint/AmbiguousRegexpLiteral:
|
147
160
|
Enabled: true
|
148
161
|
|
162
|
+
Lint/BinaryOperatorWithIdenticalOperands:
|
163
|
+
Enabled: true
|
164
|
+
|
165
|
+
Lint/DeprecatedClassMethods:
|
166
|
+
Enabled: true
|
167
|
+
|
168
|
+
Lint/DuplicateRescueException:
|
169
|
+
Enabled: true
|
170
|
+
|
149
171
|
Lint/ErbNewArguments:
|
150
172
|
Enabled: true
|
151
173
|
|
174
|
+
Lint/EmptyConditionalBody:
|
175
|
+
Enabled: true
|
176
|
+
|
177
|
+
Lint/FloatComparison:
|
178
|
+
Enabled: true
|
179
|
+
|
180
|
+
Lint/OutOfRangeRegexpRef:
|
181
|
+
Enabled: true
|
182
|
+
|
183
|
+
Lint/RedundantStringCoercion:
|
184
|
+
Enabled: true
|
185
|
+
|
152
186
|
# Use my_method(my_arg) not my_method( my_arg ) or my_method my_arg.
|
153
187
|
Lint/RequireParentheses:
|
154
188
|
Enabled: true
|
155
189
|
|
190
|
+
Lint/SelfAssignment:
|
191
|
+
Enabled: true
|
192
|
+
|
156
193
|
Lint/ShadowingOuterLocalVariable:
|
157
194
|
Enabled: true
|
158
195
|
|
159
|
-
Lint/
|
196
|
+
Lint/TopLevelReturnWithArgument:
|
197
|
+
Enabled: true
|
198
|
+
|
199
|
+
Lint/UnreachableLoop:
|
160
200
|
Enabled: true
|
161
201
|
|
162
202
|
Lint/UriEscapeUnescape:
|
@@ -165,15 +205,18 @@ Lint/UriEscapeUnescape:
|
|
165
205
|
Lint/UselessAssignment:
|
166
206
|
Enabled: true
|
167
207
|
|
168
|
-
|
208
|
+
Style/ParenthesesAroundCondition:
|
169
209
|
Enabled: true
|
170
210
|
|
171
|
-
Style/
|
211
|
+
Style/ExplicitBlockArgument:
|
172
212
|
Enabled: true
|
173
213
|
|
174
214
|
Style/FrozenStringLiteralComment:
|
175
215
|
Enabled: false
|
176
216
|
|
217
|
+
Style/GlobalStdStream:
|
218
|
+
Enabled: true
|
219
|
+
|
177
220
|
Style/HashEachMethods:
|
178
221
|
Enabled: true
|
179
222
|
|
@@ -198,6 +241,9 @@ Style/Semicolon:
|
|
198
241
|
Enabled: true
|
199
242
|
AllowAsExpressionSeparator: true
|
200
243
|
|
244
|
+
Style/StringConcatenation:
|
245
|
+
Enabled: true
|
246
|
+
|
201
247
|
# Prefer Foo.method over Foo::method
|
202
248
|
Style/ColonMethodCall:
|
203
249
|
Enabled: true
|
data/Dockerfile
ADDED
@@ -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
@@ -1,3 +1,5 @@
|
|
1
|
+
[](https://badge.fury.io/rb/puppeteer-ruby)
|
2
|
+
|
1
3
|
# Puppeteer in Ruby [UNDER HEAVY DEVELOPMENT]
|
2
4
|
|
3
5
|
A Ruby port of [puppeteer](https://pptr.dev/).
|
@@ -47,7 +49,7 @@ end
|
|
47
49
|
|
48
50
|
More usage examples can be found [here](https://github.com/YusukeIwaki/puppeteer-ruby-example)
|
49
51
|
|
50
|
-
## Collaboration with Selenium or Capybara
|
52
|
+
## :bulb: Collaboration with Selenium or Capybara
|
51
53
|
|
52
54
|
It is really remarkable that we can use puppeteer functions in existing Selenium or Capybara codes, with a few configuration in advance.
|
53
55
|
|
data/docker-compose.yml
ADDED
@@ -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
|
data/lib/puppeteer.rb
CHANGED
@@ -2,6 +2,8 @@ require 'concurrent'
|
|
2
2
|
|
3
3
|
class Puppeteer; end
|
4
4
|
|
5
|
+
require 'puppeteer/env'
|
6
|
+
|
5
7
|
# Custom data types.
|
6
8
|
require 'puppeteer/device'
|
7
9
|
require 'puppeteer/errors'
|
@@ -36,6 +38,8 @@ require 'puppeteer/mouse'
|
|
36
38
|
require 'puppeteer/network_manager'
|
37
39
|
require 'puppeteer/page'
|
38
40
|
require 'puppeteer/remote_object'
|
41
|
+
require 'puppeteer/request'
|
42
|
+
require 'puppeteer/response'
|
39
43
|
require 'puppeteer/target'
|
40
44
|
require 'puppeteer/timeout_settings'
|
41
45
|
require 'puppeteer/touch_screen'
|
@@ -49,18 +53,14 @@ require 'puppeteer/element_handle'
|
|
49
53
|
|
50
54
|
# ref: https://github.com/puppeteer/puppeteer/blob/master/lib/Puppeteer.js
|
51
55
|
class Puppeteer
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
+
def self.method_missing(method, *args, **kwargs, &block)
|
57
|
+
@puppeteer ||= Puppeteer.new(
|
58
|
+
project_root: __dir__,
|
59
|
+
preferred_revision: '706915',
|
60
|
+
is_puppeteer_core: true,
|
61
|
+
)
|
56
62
|
|
57
|
-
|
58
|
-
@instance ||= Puppeteer.new(
|
59
|
-
project_root: __dir__,
|
60
|
-
preferred_revision: '706915',
|
61
|
-
is_puppeteer_core: true,
|
62
|
-
)
|
63
|
-
end
|
63
|
+
@puppeteer.send(method, *args, **kwargs, &block)
|
64
64
|
end
|
65
65
|
|
66
66
|
# @param project_root [String]
|
@@ -166,7 +166,11 @@ class Puppeteer
|
|
166
166
|
}.compact
|
167
167
|
browser = launcher.connect(options)
|
168
168
|
if block_given?
|
169
|
-
|
169
|
+
begin
|
170
|
+
yield(browser)
|
171
|
+
ensure
|
172
|
+
browser.disconnect
|
173
|
+
end
|
170
174
|
else
|
171
175
|
browser
|
172
176
|
end
|
data/lib/puppeteer/browser.rb
CHANGED
@@ -43,7 +43,7 @@ class Puppeteer::Browser
|
|
43
43
|
@default_context = Puppeteer::BrowserContext.new(@connection, self, nil)
|
44
44
|
@contexts = {}
|
45
45
|
context_ids.each do |context_id|
|
46
|
-
@contexts[context_id] = Puppeteer::BrowserContext.new(@connection, self
|
46
|
+
@contexts[context_id] = Puppeteer::BrowserContext.new(@connection, self, context_id)
|
47
47
|
end
|
48
48
|
@targets = {}
|
49
49
|
@connection.on_event 'Events.Connection.Disconnected' do
|
@@ -70,6 +70,15 @@ class Puppeteer::Browser
|
|
70
70
|
add_event_listener(EVENT_MAPPINGS[event_name.to_sym], &block)
|
71
71
|
end
|
72
72
|
|
73
|
+
# @param event_name [Symbol]
|
74
|
+
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(", ")}")
|
77
|
+
end
|
78
|
+
|
79
|
+
observe_first(EVENT_MAPPINGS[event_name.to_sym], &block)
|
80
|
+
end
|
81
|
+
|
73
82
|
# @return [Puppeteer::BrowserRunner::BrowserProcess]
|
74
83
|
def process
|
75
84
|
@process
|
@@ -94,7 +103,7 @@ class Puppeteer::Browser
|
|
94
103
|
# @param context_id [String]
|
95
104
|
def dispose_context(context_id)
|
96
105
|
@connection.send_message('Target.disposeBrowserContext', browserContextId: context_id)
|
97
|
-
@contexts.
|
106
|
+
@contexts.delete(context_id)
|
98
107
|
end
|
99
108
|
|
100
109
|
class TargetAlreadyExistError < StandardError
|
@@ -166,7 +175,7 @@ class Puppeteer::Browser
|
|
166
175
|
end
|
167
176
|
|
168
177
|
# @return [String]
|
169
|
-
def
|
178
|
+
def ws_endpoint
|
170
179
|
@connection.url
|
171
180
|
end
|
172
181
|
|
@@ -196,7 +205,7 @@ class Puppeteer::Browser
|
|
196
205
|
|
197
206
|
# @return {!Target}
|
198
207
|
def target
|
199
|
-
targets.
|
208
|
+
targets.find { |target| target.type == 'browser' }
|
200
209
|
end
|
201
210
|
|
202
211
|
# used only in Target#opener
|
@@ -204,12 +213,11 @@ class Puppeteer::Browser
|
|
204
213
|
@targets[target_id]
|
205
214
|
end
|
206
215
|
|
207
|
-
# @param
|
208
|
-
# @
|
209
|
-
# @return {!Promise<!Target>}
|
216
|
+
# @param predicate [Proc(Puppeteer::Target -> Boolean)]
|
217
|
+
# @return [Puppeteer::Target]
|
210
218
|
def wait_for_target(predicate:, timeout: nil)
|
211
219
|
timeout_in_sec = (timeout || 30000).to_i / 1000.0
|
212
|
-
existing_target = targets.
|
220
|
+
existing_target = targets.find { |target| predicate.call(target) }
|
213
221
|
return existing_target if existing_target
|
214
222
|
|
215
223
|
event_listening_ids = []
|
@@ -233,11 +241,18 @@ class Puppeteer::Browser
|
|
233
241
|
else
|
234
242
|
target_promise.value!
|
235
243
|
end
|
244
|
+
rescue Timeout::Error
|
245
|
+
raise Puppeteer::TimeoutError.new("waiting for target failed: timeout #{timeout}ms exceeded")
|
236
246
|
ensure
|
237
247
|
remove_event_listener(*event_listening_ids)
|
238
248
|
end
|
239
249
|
end
|
240
250
|
|
251
|
+
# @!method async_wait_for_target(predicate:, timeout: nil)
|
252
|
+
#
|
253
|
+
# @param predicate [Proc(Puppeteer::Target -> Boolean)]
|
254
|
+
define_async_method :async_wait_for_target
|
255
|
+
|
241
256
|
# @return {!Promise<!Array<!Puppeteer.Page>>}
|
242
257
|
def pages
|
243
258
|
browser_contexts.flat_map(&:pages)
|
@@ -266,7 +281,19 @@ class Puppeteer::Browser
|
|
266
281
|
!@connection.closed?
|
267
282
|
end
|
268
283
|
|
284
|
+
class Version
|
285
|
+
def initialize(hash)
|
286
|
+
@protocol_version = hash['protocolVersion']
|
287
|
+
@product = hash['product']
|
288
|
+
@revision = hash['revision']
|
289
|
+
@user_agent = hash['userAgent']
|
290
|
+
@js_version = hash['jsVersion']
|
291
|
+
end
|
292
|
+
|
293
|
+
attr_reader :protocol_version, :product, :revision, :user_agent, :js_version
|
294
|
+
end
|
295
|
+
|
269
296
|
private def get_version
|
270
|
-
@connection.send_message('Browser.getVersion')
|
297
|
+
Version.new(@connection.send_message('Browser.getVersion'))
|
271
298
|
end
|
272
299
|
end
|
@@ -1,5 +1,6 @@
|
|
1
1
|
class Puppeteer::BrowserContext
|
2
2
|
include Puppeteer::EventCallbackable
|
3
|
+
using Puppeteer::DefineAsyncMethod
|
3
4
|
|
4
5
|
# @param {!Puppeteer.Connection} connection
|
5
6
|
# @param {!Browser} browser
|
@@ -10,14 +11,38 @@ class Puppeteer::BrowserContext
|
|
10
11
|
@id = context_id
|
11
12
|
end
|
12
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
|
+
# @param event_name [Symbol] either of :disconnected, :targetcreated, :targetchanged, :targetdestroyed
|
22
|
+
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(", ")}")
|
25
|
+
end
|
26
|
+
|
27
|
+
add_event_listener(EVENT_MAPPINGS[event_name.to_sym], &block)
|
28
|
+
end
|
29
|
+
|
30
|
+
# @param event_name [Symbol]
|
31
|
+
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(", ")}")
|
34
|
+
end
|
35
|
+
|
36
|
+
observe_first(EVENT_MAPPINGS[event_name.to_sym], &block)
|
37
|
+
end
|
38
|
+
|
13
39
|
# @return {!Array<!Target>} target
|
14
40
|
def targets
|
15
41
|
@browser.targets.select { |target| target.browser_context == self }
|
16
42
|
end
|
17
43
|
|
18
|
-
# @param
|
19
|
-
# @
|
20
|
-
# @return {!Promise<!Target>}
|
44
|
+
# @param predicate [Proc(Puppeteer::Target -> Boolean)]
|
45
|
+
# @return [Puppeteer::Target]
|
21
46
|
def wait_for_target(predicate:, timeout: nil)
|
22
47
|
@browser.wait_for_target(
|
23
48
|
predicate: ->(target) { target.browser_context == self && predicate.call(target) },
|
@@ -25,13 +50,18 @@ class Puppeteer::BrowserContext
|
|
25
50
|
)
|
26
51
|
end
|
27
52
|
|
53
|
+
# @!method async_wait_for_target(predicate:, timeout: nil)
|
54
|
+
#
|
55
|
+
# @param predicate [Proc(Puppeteer::Target -> Boolean)]
|
56
|
+
define_async_method :async_wait_for_target
|
57
|
+
|
28
58
|
# @return {!Promise<!Array<!Puppeteer.Page>>}
|
29
59
|
def pages
|
30
60
|
targets.select { |target| target.type == 'page' }.map(&:page).reject { |page| !page }
|
31
61
|
end
|
32
62
|
|
33
63
|
def incognito?
|
34
|
-
|
64
|
+
!!@id
|
35
65
|
end
|
36
66
|
|
37
67
|
# /**
|
@@ -82,7 +112,7 @@ class Puppeteer::BrowserContext
|
|
82
112
|
end
|
83
113
|
|
84
114
|
def close
|
85
|
-
|
115
|
+
unless @id
|
86
116
|
raise 'Non-incognito profiles cannot be closed!'
|
87
117
|
end
|
88
118
|
@browser.dispose_context(@id)
|