Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@
`429 Too Many Requests` for a full remote browser service, and exposes it as `#status`

### Fixed
- `workers` skips detached workers, `target.worker` with no session raises `NoSuchTargetError` instead of a CDP error
- `attach_target` reuses a target's session and returns the target, instead of opening one more that reruns extensions
- Service workers registered by a page stayed attached and alive for the browser's lifetime, now Chrome can stop them
- An out-of-process iframe kept its parent page's session when `Target.targetCreated` came before
Expand Down
5 changes: 3 additions & 2 deletions lib/ferrum/context.rb
Original file line number Diff line number Diff line change
Expand Up @@ -56,11 +56,12 @@ def pages
@targets.values.select(&:page?).map(&:page)
end

# Dedicated and shared workers spawned by any page in this context.
# Dedicated and shared workers spawned by any page in this context,
# leaving out the ones we have no session with, e.g. detached ones.
#
# @return [Array<Worker>]
def workers
@targets.values.select { |t| t.worker? || t.shared_worker? }.map(&:worker)
@targets.values.select { |t| (t.worker? || t.shared_worker?) && t.session_id }.map(&:worker)
end

# Service worker targets registered in this context. Unlike {#workers},
Expand Down
7 changes: 7 additions & 0 deletions lib/ferrum/target.rb
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,9 @@ def page
# Connects to and returns this target's {Worker}.
#
# @return [Worker]
#
# @raise [NoSuchTargetError] if there's no session with the target, e.g. a service worker
# not attached to with {Context#attach_target}.
def worker
@worker ||= build_worker
end
Expand Down Expand Up @@ -82,6 +85,10 @@ def build_page(**options)
#
# @return [Worker]
def build_worker
if options.flatten && session_id.nil?
raise NoSuchTargetError, "No session with #{type} #{id}, attach to it with Context#attach_target first"
end

Worker.new(client, target_id: id, url: url)
end

Expand Down
26 changes: 26 additions & 0 deletions spec/worker_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,23 @@ def wait_for_target(&block)
wait_for { worker.console.map(&:text) }.to eq(["from worker"])
expect(worker.console.first).to be_warning
end

it "is left out of Context#workers once detached" do
page.go_to

page.execute <<~JS
new Worker(URL.createObjectURL(new Blob(
["self.onmessage = () => {}"],
{ type: "application/javascript" }
)))
JS

target = wait_for_target(&:worker?)
wait_for { browser.workers }.to contain_exactly(target.worker)
page.command("Target.detachFromTarget", sessionId: target.session_id)

wait_for { browser.workers }.to be_empty
end
end

describe "shared workers" do
Expand Down Expand Up @@ -95,6 +112,15 @@ def wait_for_target(&block)
expect(target.session_id).to be_nil
end

it "raises when connected to without attaching first" do
page.go_to
page.evaluate_async(%(navigator.serviceWorker.register("/sw.js").then(arguments[0])), 5)
target = wait_for_target(&:service_worker?)
wait_for { target.session_id }.to be_nil

expect { target.worker }.to raise_error(Ferrum::NoSuchTargetError, /attach_target/)
end

it "connects on demand through Context#attach_target, keeping it alive" do
page.go_to
page.evaluate_async(%(navigator.serviceWorker.register("/sw.js").then(arguments[0])), 5)
Expand Down
Loading