Workers
Ferrum discovers dedicated workers (new Worker), shared workers (new SharedWorker) and service workers
(navigator.serviceWorker.register) spawned anywhere in a context.
Dedicated and shared workers are connected to automatically as soon as they're discovered, there's no need to wait
for them. Service workers are treated differently: attaching to a service worker's session prevents Chrome from ever
terminating it while the connection stays open, so Ferrum only discovers them and leaves the connection alone unless
you explicitly ask for it with attach_target.
workers : Array<Worker>
Returns all dedicated and shared workers spawned by pages in this context, already connected.
page.execute <<~JS
new Worker(URL.createObjectURL(new Blob(
["self.onmessage = () => self.postMessage(1 + 1)"],
{ type: "application/javascript" }
)))
JS
sleep 0.1 # give Ferrum a moment to discover and connect to it
worker = browser.workers.first # => #<Ferrum::Worker @target_id="..." @url="blob:...">
worker.evaluate("1 + 1") # => 2
service_workers : Array<Target>
Returns service worker targets registered in this context. Unlike workers, these are plain Target objects and
are not connected to -- call attach_target first if you want to interact with one.
page.evaluate_async(%(navigator.serviceWorker.register("/sw.js").then(arguments[0])), 5)
sleep 0.1
target = browser.service_workers.first # => #<Ferrum::Target @id="..." @type="service_worker">
target.connected? # => false
attach_target(target_id) : Boolean
Manually attaches to a target discovered via service_workers. Once attached, target.worker returns a connected
Worker for it, same as for a dedicated or shared worker.
target = browser.service_workers.first
browser.attach_target(target.id)
target.worker.evaluate("1 + 1") # => 2
Keep in mind this keeps the service worker alive for as long as the connection is open -- only attach to the ones you actually intend to talk to.
Worker
A dedicated or shared Worker spawned by a page. Unlike Page it has no DOM, frames, mouse/keyboard, or navigation
history -- just a single global execution context and its own network activity, reachable through worker.network.
target_id : String
The worker's CDP target id.
url : String
The worker's script URL, e.g. a blob: URL for workers created from an inline Blob, as is common for
dedicated/shared workers.
network : Network
Same API as page.network -- see Network. Useful for asserting on requests a worker made on
its own, independently of the page that spawned it.
worker.network.wait_for_idle
worker.network.traffic # => [#<Ferrum::Network::Exchange, ...]
evaluate / execute / evaluate_async
Same API as on Page/Frame -- see JavaScript. A worker has a single execution context,
so there's no frame to target.
worker.evaluate("1 + 1") # => 2
on(:request) / on(:auth)
Subscribe to the worker's own network interception events, same as page.on(:request) -- see the intercept method
in Network.
close : Boolean
Closes the underlying CDP target and the worker's own connection.
worker.close
Example
Spawn a page's worker, wait for Ferrum to discover it, and read back a result it computes and posts to the page:
page.go_to
page.execute <<~JS
window.worker = new Worker(URL.createObjectURL(new Blob(
["self.onmessage = (e) => self.postMessage(e.data * 2)"],
{ type: "application/javascript" }
)))
window.worker.onmessage = (e) => { window.result = e.data }
JS
worker = nil
until worker
worker = browser.workers.first
sleep 0.05
end
page.execute("window.worker.postMessage(21)")
sleep 0.1
page.evaluate("window.result") # => 42