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
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,13 @@

### Added


### Changed

### Fixed
- Full-page screenshots no longer resize the window, preventing focus steal on macOS [#580]
- DOM.enable is now has `includeWhitespace: "all"` to keep track of new line nodes which previously were resolved to 0, and errored with NodeNotFoundError [#596]
- `DOM.requestNode` call is moved to the node class and being done lazily, this reduces number of intermediate node ids sent by backend to frontend [#596]

### Removed

Expand Down
2 changes: 1 addition & 1 deletion Gemfile
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ gem "rspec", "~> 3.8"
gem "rspec-wait"
gem "rubocop", "~> 1.22"
gem "rubocop-rake", require: false
gem "sinatra", "~> 3.2"
gem "sinatra", "~> 4.0"
gem "yard", "~> 0.9", require: false

gemspec
9 changes: 2 additions & 7 deletions lib/ferrum/frame/runtime.rb
Original file line number Diff line number Diff line change
Expand Up @@ -152,13 +152,8 @@ def handle_response(response)

case response["subtype"]
when "node"
# We cannot store object_id in the node because page can be reloaded
# and node destroyed so we need to retrieve it each time for given id.
# Though we can try to subscribe to `DOM.childNodeRemoved` and
# `DOM.childNodeInserted` in the future.
node_id = @page.command("DOM.requestNode", objectId: object_id)["nodeId"]
description = @page.command("DOM.describeNode", nodeId: node_id)["node"]
Node.new(self, @page.target_id, node_id, description)
description = @page.command("DOM.describeNode", objectId: object_id)["node"]
Node.new(self, @page.target_id, description, object_id: object_id)
when "array"
reduce_props(object_id, []) do |memo, key, value|
next(memo) unless Integer(key, exception: false)
Expand Down
21 changes: 18 additions & 3 deletions lib/ferrum/node.rb
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,29 @@ class Node
MOVING_WAIT_DELAY = ENV.fetch("FERRUM_NODE_MOVING_WAIT", 0.01).to_f
MOVING_WAIT_ATTEMPTS = ENV.fetch("FERRUM_NODE_MOVING_ATTEMPTS", 50).to_i

attr_reader :page, :target_id, :node_id, :description, :tag_name
attr_reader :page, :target_id, :description, :tag_name

def initialize(frame, target_id, node_id, description)
def initialize(frame, target_id, description, object_id: nil, node_id: nil)
@page = frame.page
@target_id = target_id
@node_id = node_id
@description = description
@tag_name = description["nodeName"].downcase
@object_id = object_id
@node_id = node_id
end

# Frontend node id is resolved lazily, on first actual need (focus, click, scroll_into_view, etc.)
# We can try to subscribe to `DOM.childNodeRemoved` and `DOM.childNodeInserted` in the future
# to keep track of nodes.
def node_id
@node_id ||= begin
id = page.command("DOM.requestNode", objectId: @object_id)["nodeId"]
raise NodeNotFoundError, "node is not trackable" if id.zero?

id
rescue NoExecutionContextError
raise NodeNotFoundError, "node is not trackable"
end
end

def node?
Expand Down
2 changes: 1 addition & 1 deletion lib/ferrum/page.rb
Original file line number Diff line number Diff line change
Expand Up @@ -459,7 +459,7 @@ def subscribe
def prepare_page
command("Page.enable")
command("Runtime.enable")
command("DOM.enable")
command("DOM.enable", includeWhitespace: "all")
command("CSS.enable")
command("Log.enable")
command("Network.enable")
Expand Down
7 changes: 5 additions & 2 deletions sig/ferrum/node.rbs
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,13 @@ module Ferrum

MOVING_WAIT_ATTEMPTS: untyped

@node_id: untyped
@object_id: untyped

attr_reader page: untyped

attr_reader target_id: untyped

attr_reader node_id: untyped

attr_reader description: untyped

attr_reader tag_name: untyped
Expand All @@ -26,6 +27,8 @@ module Ferrum

def focusable?: () -> untyped

def node_id: -> untyped

def wait_for_stop_moving: (?delay: untyped, ?attempts: untyped) -> untyped

def moving?: (?delay: untyped) -> untyped
Expand Down
20 changes: 20 additions & 0 deletions spec/node_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,15 @@
expect(links.size).to eq(1)
expect(links.first.text).to eq("Open for match")
end

it "works with whitespace nodes" do
browser.go_to("/ws_node")

values = browser.xpath("//li//text()").map(&:text)

expect(values.size).to eq(5)
expect(values).to eq(["\n ", "\n ", "b", "\n ", "\n "])
end
end

describe "#at_css" do
Expand Down Expand Up @@ -854,5 +863,16 @@

expect { node.text }.to raise_error(Ferrum::NodeNotFoundError)
end

it "works for a new node after refresh" do
browser.go_to("/index")
shallow_node = browser.at_xpath(".//a")

browser.refresh
expect { shallow_node.click }.to raise_error(Ferrum::NodeNotFoundError)

node = browser.at_xpath(".//a")
expect { node.click }.not_to raise_error(Ferrum::NodeNotFoundError)
end
end
end
12 changes: 12 additions & 0 deletions spec/support/views/ws_node.erb
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
<!DOCTYPE html>
<html lang="ru">
<body>
<ul>
<li>
<div>
<span>b</span>
</div>
</li>
</ul>
</body>
</html>
Loading