puppeteer-ruby 0.0.21 → 0.0.27
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.circleci/config.yml +32 -22
- data/.github/workflows/reviewdog.yml +1 -1
- data/.rubocop.yml +37 -0
- data/CHANGELOG.md +74 -0
- data/Dockerfile +1 -1
- data/README.md +15 -0
- data/lib/puppeteer.rb +9 -2
- data/lib/puppeteer/browser.rb +19 -28
- data/lib/puppeteer/browser_context.rb +48 -49
- data/lib/puppeteer/browser_runner.rb +19 -5
- data/lib/puppeteer/cdp_session.rb +11 -7
- data/lib/puppeteer/concurrent_ruby_utils.rb +22 -6
- data/lib/puppeteer/connection.rb +30 -11
- data/lib/puppeteer/define_async_method.rb +15 -6
- data/lib/puppeteer/dom_world.rb +2 -2
- data/lib/puppeteer/event_callbackable.rb +4 -0
- data/lib/puppeteer/events.rb +184 -0
- data/lib/puppeteer/exception_details.rb +38 -0
- data/lib/puppeteer/frame_manager.rb +20 -16
- data/lib/puppeteer/geolocation.rb +24 -0
- data/lib/puppeteer/launcher.rb +0 -1
- data/lib/puppeteer/launcher/browser_options.rb +2 -1
- data/lib/puppeteer/launcher/chrome.rb +4 -8
- data/lib/puppeteer/launcher/firefox.rb +4 -8
- data/lib/puppeteer/lifecycle_watcher.rb +6 -6
- data/lib/puppeteer/network_manager.rb +6 -6
- data/lib/puppeteer/page.rb +119 -141
- data/lib/puppeteer/page/screenshot_options.rb +2 -2
- data/lib/puppeteer/page/screenshot_task_queue.rb +13 -0
- data/lib/puppeteer/target.rb +4 -6
- data/lib/puppeteer/version.rb +1 -1
- data/puppeteer-ruby.gemspec +6 -4
- metadata +43 -10
@@ -14,16 +14,24 @@ class Puppeteer::BrowserRunner
|
|
14
14
|
@proc = nil
|
15
15
|
@connection = nil
|
16
16
|
@closed = true
|
17
|
-
@listeners = []
|
18
17
|
end
|
19
18
|
|
20
19
|
attr_reader :proc, :connection
|
21
20
|
|
22
21
|
class BrowserProcess
|
23
22
|
def initialize(env, executable_path, args)
|
23
|
+
@spawnargs =
|
24
|
+
if args && !args.empty?
|
25
|
+
[executable_path] + args
|
26
|
+
else
|
27
|
+
[executable_path]
|
28
|
+
end
|
29
|
+
|
24
30
|
stdin, @stdout, @stderr, @thread = Open3.popen3(env, executable_path, *args)
|
25
31
|
stdin.close
|
26
32
|
@pid = @thread.pid
|
33
|
+
rescue Errno::ENOENT => err
|
34
|
+
raise LaunchError.new(err.message)
|
27
35
|
end
|
28
36
|
|
29
37
|
def kill
|
@@ -37,7 +45,13 @@ class Puppeteer::BrowserRunner
|
|
37
45
|
@thread.join
|
38
46
|
end
|
39
47
|
|
40
|
-
attr_reader :stdout, :stderr
|
48
|
+
attr_reader :stdout, :stderr, :spawnargs
|
49
|
+
end
|
50
|
+
|
51
|
+
class LaunchError < StandardError
|
52
|
+
def initialize(reason)
|
53
|
+
super("Failed to launch browser! #{reason}")
|
54
|
+
end
|
41
55
|
end
|
42
56
|
|
43
57
|
# @param {!(Launcher.LaunchOptions)=} options
|
@@ -123,12 +137,12 @@ class Puppeteer::BrowserRunner
|
|
123
137
|
|
124
138
|
# @return {Promise}
|
125
139
|
def kill
|
126
|
-
unless @closed
|
127
|
-
@proc.kill
|
128
|
-
end
|
129
140
|
if @temp_directory
|
130
141
|
FileUtils.rm_rf(@temp_directory)
|
131
142
|
end
|
143
|
+
unless @closed
|
144
|
+
@proc.kill
|
145
|
+
end
|
132
146
|
end
|
133
147
|
|
134
148
|
|
@@ -9,7 +9,7 @@ class Puppeteer::CDPSession
|
|
9
9
|
# @param {string} targetType
|
10
10
|
# @param {string} sessionId
|
11
11
|
def initialize(connection, target_type, session_id)
|
12
|
-
@callbacks =
|
12
|
+
@callbacks = Concurrent::Hash.new
|
13
13
|
@connection = connection
|
14
14
|
@target_type = target_type
|
15
15
|
@session_id = session_id
|
@@ -31,10 +31,14 @@ class Puppeteer::CDPSession
|
|
31
31
|
if !@connection
|
32
32
|
raise Error.new("Protocol error (#{method}): Session closed. Most likely the #{@target_type} has been closed.")
|
33
33
|
end
|
34
|
-
|
34
|
+
|
35
35
|
promise = resolvable_future
|
36
|
-
|
37
|
-
@
|
36
|
+
|
37
|
+
@connection.generate_id do |id|
|
38
|
+
@callbacks[id] = Puppeteer::Connection::MessageCallback.new(method: method, promise: promise)
|
39
|
+
@connection.raw_send(id: id, message: { sessionId: @session_id, method: method, params: params })
|
40
|
+
end
|
41
|
+
|
38
42
|
promise
|
39
43
|
end
|
40
44
|
|
@@ -44,10 +48,10 @@ class Puppeteer::CDPSession
|
|
44
48
|
if callback = @callbacks.delete(message['id'])
|
45
49
|
callback_with_message(callback, message)
|
46
50
|
else
|
47
|
-
raise Error.new("unknown id: #{id}")
|
51
|
+
raise Error.new("unknown id: #{message['id']}")
|
48
52
|
end
|
49
53
|
else
|
50
|
-
emit_event
|
54
|
+
emit_event(message['method'], message['params'])
|
51
55
|
end
|
52
56
|
end
|
53
57
|
|
@@ -79,7 +83,7 @@ class Puppeteer::CDPSession
|
|
79
83
|
end
|
80
84
|
@callbacks.clear
|
81
85
|
@connection = nil
|
82
|
-
emit_event
|
86
|
+
emit_event(CDPSessionEmittedEvents::Disconnected)
|
83
87
|
end
|
84
88
|
|
85
89
|
# @param event_name [String]
|
@@ -4,9 +4,13 @@ module Puppeteer::ConcurrentRubyUtils
|
|
4
4
|
# REMARK: This method doesn't assure the order of calling.
|
5
5
|
# for example, await_all(async1, async2) calls calls2 -> calls1 often.
|
6
6
|
def await_all(*args)
|
7
|
-
if args.length == 1 && args
|
8
|
-
|
7
|
+
if args.length == 1 && args.first.is_a?(Enumerable)
|
8
|
+
await_all(*args.first)
|
9
9
|
else
|
10
|
+
if args.any? { |arg| !arg.is_a?(Concurrent::Promises::Future) }
|
11
|
+
raise ArgumentError.new("All argument must be a Future: #{args}")
|
12
|
+
end
|
13
|
+
|
10
14
|
Concurrent::Promises.zip(*args).value!
|
11
15
|
end
|
12
16
|
end
|
@@ -15,9 +19,13 @@ module Puppeteer::ConcurrentRubyUtils
|
|
15
19
|
# REMARK: This method doesn't assure the order of calling.
|
16
20
|
# for example, await_all(async1, async2) calls calls2 -> calls1 often.
|
17
21
|
def await_any(*args)
|
18
|
-
if args.length == 1 && args
|
19
|
-
|
22
|
+
if args.length == 1 && args.first.is_a?(Enumerable)
|
23
|
+
await_any(*args.first)
|
20
24
|
else
|
25
|
+
if args.any? { |arg| !arg.is_a?(Concurrent::Promises::Future) }
|
26
|
+
raise ArgumentError.new("All argument must be a Future: #{args}")
|
27
|
+
end
|
28
|
+
|
21
29
|
Concurrent::Promises.any(*args).value!
|
22
30
|
end
|
23
31
|
end
|
@@ -31,8 +39,16 @@ module Puppeteer::ConcurrentRubyUtils
|
|
31
39
|
end
|
32
40
|
end
|
33
41
|
|
34
|
-
def future(&block)
|
35
|
-
Concurrent::Promises.future(
|
42
|
+
def future(*args, &block)
|
43
|
+
Concurrent::Promises.future(*args) do |*block_args|
|
44
|
+
block.call(*block_args)
|
45
|
+
rescue Puppeteer::TimeoutError
|
46
|
+
# suppress error logging
|
47
|
+
raise
|
48
|
+
rescue => err
|
49
|
+
Logger.new($stderr).warn(err)
|
50
|
+
raise err
|
51
|
+
end
|
36
52
|
end
|
37
53
|
|
38
54
|
def resolvable_future(&block)
|
data/lib/puppeteer/connection.rb
CHANGED
@@ -39,7 +39,7 @@ class Puppeteer::Connection
|
|
39
39
|
def initialize(url, transport, delay = 0)
|
40
40
|
@url = url
|
41
41
|
@last_id = 0
|
42
|
-
@callbacks =
|
42
|
+
@callbacks = Concurrent::Hash.new
|
43
43
|
@delay = delay
|
44
44
|
|
45
45
|
@transport = transport
|
@@ -52,7 +52,7 @@ class Puppeteer::Connection
|
|
52
52
|
handle_close
|
53
53
|
end
|
54
54
|
|
55
|
-
@sessions =
|
55
|
+
@sessions = Concurrent::Hash.new
|
56
56
|
@closed = false
|
57
57
|
end
|
58
58
|
|
@@ -92,22 +92,41 @@ class Puppeteer::Connection
|
|
92
92
|
end
|
93
93
|
|
94
94
|
def async_send_message(method, params = {})
|
95
|
-
id = raw_send(message: { method: method, params: params })
|
96
95
|
promise = resolvable_future
|
97
|
-
|
96
|
+
|
97
|
+
generate_id do |id|
|
98
|
+
@callbacks[id] = MessageCallback.new(method: method, promise: promise)
|
99
|
+
raw_send(id: id, message: { method: method, params: params })
|
100
|
+
end
|
101
|
+
|
98
102
|
promise
|
99
103
|
end
|
100
104
|
|
101
|
-
private
|
102
|
-
|
105
|
+
# package private. not intended to use externally.
|
106
|
+
#
|
107
|
+
# ```usage
|
108
|
+
# connection.generate_id do |generated_id|
|
109
|
+
# # play with generated_id
|
110
|
+
# end
|
111
|
+
# ````
|
112
|
+
#
|
113
|
+
def generate_id(&block)
|
114
|
+
block.call(@last_id += 1)
|
103
115
|
end
|
104
116
|
|
105
|
-
|
106
|
-
|
117
|
+
# package private. not intended to use externally.
|
118
|
+
def raw_send(id:, message:)
|
119
|
+
# In original puppeteer (JS) implementation,
|
120
|
+
# id is generated here using #generate_id and the id argument is not passed to #raw_send.
|
121
|
+
#
|
122
|
+
# However with concurrent-ruby, '#handle_message' is sometimes called
|
123
|
+
# just soon after @transport.send_text and **before returning the id.**
|
124
|
+
#
|
125
|
+
# So we have to know the message id in advance before send_text.
|
126
|
+
#
|
107
127
|
payload = JSON.fast_generate(message.compact.merge(id: id))
|
108
128
|
@transport.send_text(payload)
|
109
129
|
request_debug_printer.handle_payload(payload)
|
110
|
-
id
|
111
130
|
end
|
112
131
|
|
113
132
|
# Just for effective debugging :)
|
@@ -211,7 +230,7 @@ class Puppeteer::Connection
|
|
211
230
|
end
|
212
231
|
end
|
213
232
|
else
|
214
|
-
emit_event
|
233
|
+
emit_event(message['method'], message['params'])
|
215
234
|
end
|
216
235
|
end
|
217
236
|
|
@@ -233,7 +252,7 @@ class Puppeteer::Connection
|
|
233
252
|
session.handle_closed
|
234
253
|
end
|
235
254
|
@sessions.clear
|
236
|
-
emit_event
|
255
|
+
emit_event(ConnectionEmittedEvents::Disconnected)
|
237
256
|
end
|
238
257
|
|
239
258
|
def on_close(&block)
|
@@ -10,12 +10,21 @@ module Puppeteer::DefineAsyncMethod
|
|
10
10
|
end
|
11
11
|
|
12
12
|
original_method = instance_method(async_method_name[6..-1])
|
13
|
-
define_method(async_method_name) do |*args|
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
13
|
+
define_method(async_method_name) do |*args, **kwargs|
|
14
|
+
if kwargs.empty? # for Ruby < 2.7
|
15
|
+
Concurrent::Promises.future do
|
16
|
+
original_method.bind(self).call(*args)
|
17
|
+
rescue => err
|
18
|
+
Logger.new($stderr).warn(err)
|
19
|
+
raise err
|
20
|
+
end
|
21
|
+
else
|
22
|
+
Concurrent::Promises.future do
|
23
|
+
original_method.bind(self).call(*args, **kwargs)
|
24
|
+
rescue => err
|
25
|
+
Logger.new($stderr).warn(err)
|
26
|
+
raise err
|
27
|
+
end
|
19
28
|
end
|
20
29
|
end
|
21
30
|
end
|
data/lib/puppeteer/dom_world.rb
CHANGED
@@ -134,7 +134,7 @@ class Puppeteer::DOMWorld
|
|
134
134
|
|
135
135
|
# @return [String]
|
136
136
|
def content
|
137
|
-
evaluate
|
137
|
+
evaluate(<<-JAVASCRIPT)
|
138
138
|
() => {
|
139
139
|
let retVal = '';
|
140
140
|
if (document.doctype)
|
@@ -151,7 +151,7 @@ class Puppeteer::DOMWorld
|
|
151
151
|
# @param wait_until [String|Array<String>]
|
152
152
|
def set_content(html, timeout: nil, wait_until: nil)
|
153
153
|
option_wait_until = [wait_until || 'load'].flatten
|
154
|
-
option_timeout = @timeout_settings.navigation_timeout
|
154
|
+
option_timeout = timeout || @timeout_settings.navigation_timeout
|
155
155
|
|
156
156
|
# We rely upon the fact that document.open() will reset frame lifecycle with "init"
|
157
157
|
# lifecycle event. @see https://crrev.com/608658
|
@@ -31,6 +31,8 @@ module Puppeteer::EventCallbackable
|
|
31
31
|
(@event_listeners[event_name] ||= EventListeners.new).add(&block)
|
32
32
|
end
|
33
33
|
|
34
|
+
alias_method :on, :add_event_listener
|
35
|
+
|
34
36
|
def remove_event_listener(*id_args)
|
35
37
|
(@event_listeners ||= {}).each do |event_name, listeners|
|
36
38
|
id_args.each do |id|
|
@@ -50,6 +52,8 @@ module Puppeteer::EventCallbackable
|
|
50
52
|
end
|
51
53
|
end
|
52
54
|
|
55
|
+
alias_method :once, :observe_first
|
56
|
+
|
53
57
|
def on_event(event_name, &block)
|
54
58
|
@event_callbackable_handlers ||= {}
|
55
59
|
@event_callbackable_handlers[event_name] = block
|
@@ -0,0 +1,184 @@
|
|
1
|
+
require 'digest/md5'
|
2
|
+
|
3
|
+
module EventsDefinitionUtils
|
4
|
+
refine Kernel do
|
5
|
+
# Symbol is used to prevent external parties listening to these events
|
6
|
+
def Symbol(str)
|
7
|
+
Digest::MD5.hexdigest(str)
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
refine Hash do
|
12
|
+
def define_const_into(target_module)
|
13
|
+
each do |key, value|
|
14
|
+
target_module.const_set(key, value)
|
15
|
+
target_module.define_singleton_method(key) { value }
|
16
|
+
end
|
17
|
+
keyset = Set.new(keys)
|
18
|
+
valueset = Set.new(values)
|
19
|
+
target_module.define_singleton_method(:keys) { keyset }
|
20
|
+
target_module.define_singleton_method(:values) { valueset }
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
using EventsDefinitionUtils
|
26
|
+
|
27
|
+
# Internal events that the Connection class emits.
|
28
|
+
module ConnectionEmittedEvents ; end
|
29
|
+
|
30
|
+
{
|
31
|
+
Disconnected: Symbol('Connection.Disconnected'),
|
32
|
+
}.define_const_into(ConnectionEmittedEvents)
|
33
|
+
|
34
|
+
# Internal events that the CDPSession class emits.
|
35
|
+
module CDPSessionEmittedEvents ; end
|
36
|
+
|
37
|
+
{
|
38
|
+
Disconnected: Symbol('CDPSession.Disconnected'),
|
39
|
+
}.define_const_into(CDPSessionEmittedEvents)
|
40
|
+
|
41
|
+
# All the events a Browser may emit.
|
42
|
+
module BrowserEmittedEvents ; end
|
43
|
+
|
44
|
+
{
|
45
|
+
# Emitted when Puppeteer gets disconnected from the Chromium instance. This might happen because of one of the following:
|
46
|
+
# - Chromium is closed or crashed
|
47
|
+
# - The Browser#disconnect method was called.
|
48
|
+
Disconnected: 'disconnected',
|
49
|
+
|
50
|
+
# Emitted when the url of a target changes. Contains a {@link Target} instance.
|
51
|
+
TargetChanged: 'targetchanged',
|
52
|
+
|
53
|
+
# Emitted when a target is created, for example when a new page is opened by
|
54
|
+
# window.open or by Browser#newPage
|
55
|
+
# Contains a Target instance.
|
56
|
+
TargetCreated: 'targetcreated',
|
57
|
+
|
58
|
+
# Emitted when a target is destroyed, for example when a page is closed.
|
59
|
+
# Contains a Target instance.
|
60
|
+
TargetDestroyed: 'targetdestroyed',
|
61
|
+
}.define_const_into(BrowserEmittedEvents)
|
62
|
+
|
63
|
+
module BrowserContextEmittedEvents ; end
|
64
|
+
|
65
|
+
{
|
66
|
+
# Emitted when the url of a target inside the browser context changes.
|
67
|
+
# Contains a Target instance.
|
68
|
+
TargetChanged: 'targetchanged',
|
69
|
+
|
70
|
+
# Emitted when a target is created, for example when a new page is opened by
|
71
|
+
# window.open or by BrowserContext#newPage
|
72
|
+
# Contains a Target instance.
|
73
|
+
TargetCreated: 'targetcreated',
|
74
|
+
|
75
|
+
# Emitted when a target is destroyed within the browser context, for example when a page is closed.
|
76
|
+
# Contains a Target instance.
|
77
|
+
TargetDestroyed: 'targetdestroyed',
|
78
|
+
}.define_const_into(BrowserContextEmittedEvents)
|
79
|
+
|
80
|
+
# We use symbols to prevent any external parties listening to these events.
|
81
|
+
# They are internal to Puppeteer.
|
82
|
+
module NetworkManagerEmittedEvents ; end
|
83
|
+
|
84
|
+
{
|
85
|
+
Request: Symbol('NetworkManager.Request'),
|
86
|
+
Response: Symbol('NetworkManager.Response'),
|
87
|
+
RequestFailed: Symbol('NetworkManager.RequestFailed'),
|
88
|
+
RequestFinished: Symbol('NetworkManager.RequestFinished'),
|
89
|
+
}.define_const_into(NetworkManagerEmittedEvents)
|
90
|
+
|
91
|
+
|
92
|
+
# We use symbols to prevent external parties listening to these events.
|
93
|
+
# They are internal to Puppeteer.
|
94
|
+
module FrameManagerEmittedEvents ; end
|
95
|
+
|
96
|
+
{
|
97
|
+
FrameAttached: Symbol('FrameManager.FrameAttached'),
|
98
|
+
FrameNavigated: Symbol('FrameManager.FrameNavigated'),
|
99
|
+
FrameDetached: Symbol('FrameManager.FrameDetached'),
|
100
|
+
LifecycleEvent: Symbol('FrameManager.LifecycleEvent'),
|
101
|
+
FrameNavigatedWithinDocument: Symbol('FrameManager.FrameNavigatedWithinDocument'),
|
102
|
+
ExecutionContextCreated: Symbol('FrameManager.ExecutionContextCreated'),
|
103
|
+
ExecutionContextDestroyed: Symbol('FrameManager.ExecutionContextDestroyed'),
|
104
|
+
}.define_const_into(FrameManagerEmittedEvents)
|
105
|
+
|
106
|
+
# All the events that a page instance may emit.
|
107
|
+
module PageEmittedEvents ; end
|
108
|
+
|
109
|
+
{
|
110
|
+
# Emitted when the page closes.
|
111
|
+
Close: 'close',
|
112
|
+
|
113
|
+
# Emitted when JavaScript within the page calls one of console API methods,
|
114
|
+
# e.g. `console.log` or `console.dir`. Also emitted if the page throws an
|
115
|
+
# error or a warning.
|
116
|
+
Console: 'console',
|
117
|
+
|
118
|
+
# Emitted when a JavaScript dialog appears, such as `alert`, `prompt`,
|
119
|
+
# `confirm` or `beforeunload`. Puppeteer can respond to the dialog via
|
120
|
+
# Dialog#accept or Dialog#dismiss.
|
121
|
+
Dialog: 'dialog',
|
122
|
+
|
123
|
+
# Emitted when the JavaScript
|
124
|
+
# {https://developer.mozilla.org/en-US/docs/Web/Events/DOMContentLoaded DOMContentLoaded} event is dispatched.
|
125
|
+
DOMContentLoaded: 'domcontentloaded',
|
126
|
+
|
127
|
+
# Emitted when the page crashes. Will contain an `Error`.
|
128
|
+
Error: 'error',
|
129
|
+
|
130
|
+
# Emitted when a frame is attached. Will contain a Frame.
|
131
|
+
FrameAttached: 'frameattached',
|
132
|
+
# Emitted when a frame is detached. Will contain a Frame.
|
133
|
+
FrameDetached: 'framedetached',
|
134
|
+
# Emitted when a frame is navigated to a new URL. Will contain a {@link Frame}.
|
135
|
+
FrameNavigated: 'framenavigated',
|
136
|
+
|
137
|
+
# Emitted when the JavaScript
|
138
|
+
# {https://developer.mozilla.org/en-US/docs/Web/Events/load | load} event is dispatched.
|
139
|
+
Load: 'load',
|
140
|
+
|
141
|
+
# Emitted when the JavaScript code makes a call to `console.timeStamp`. For
|
142
|
+
# the list of metrics see {@link Page.metrics | page.metrics}.
|
143
|
+
#
|
144
|
+
# Contains an object with two properties:
|
145
|
+
# - `title`: the title passed to `console.timeStamp`
|
146
|
+
# - `metrics`: objec containing metrics as key/value pairs. The values will be `number`s.
|
147
|
+
Metrics: 'metrics',
|
148
|
+
|
149
|
+
# Emitted when an uncaught exception happens within the page.
|
150
|
+
# Contains an `Error`.
|
151
|
+
PageError: 'pageerror',
|
152
|
+
|
153
|
+
# Emitted when the page opens a new tab or window.
|
154
|
+
# Contains a Page corresponding to the popup window.
|
155
|
+
Popup: 'popup',
|
156
|
+
|
157
|
+
# Emitted when a page issues a request and contains a HTTPRequest.
|
158
|
+
#
|
159
|
+
# The object is readonly. See Page#setRequestInterception for intercepting and mutating requests.
|
160
|
+
Request: 'request',
|
161
|
+
|
162
|
+
# Emitted when a request fails, for example by timing out.
|
163
|
+
#
|
164
|
+
# Contains a HTTPRequest.
|
165
|
+
#
|
166
|
+
# NOTE: HTTP Error responses, such as 404 or 503, are still successful
|
167
|
+
# responses from HTTP standpoint, so request will complete with
|
168
|
+
# `requestfinished` event and not with `requestfailed`.
|
169
|
+
RequestFailed: 'requestfailed',
|
170
|
+
|
171
|
+
# Emitted when a request finishes successfully. Contains a HTTPRequest.
|
172
|
+
RequestFinished: 'requestfinished',
|
173
|
+
|
174
|
+
# Emitted when a response is received. Contains a HTTPResponse.
|
175
|
+
Response: 'response',
|
176
|
+
|
177
|
+
# Emitted when a dedicated
|
178
|
+
# {https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API WebWorker} is spawned by the page.
|
179
|
+
WorkerCreated: 'workercreated',
|
180
|
+
|
181
|
+
# Emitted when a dedicated
|
182
|
+
# {https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API WebWorker} is destroyed by the page.
|
183
|
+
WorkerDestroyed: 'workerdestroyed',
|
184
|
+
}.define_const_into(PageEmittedEvents)
|