lib/capybara/webkit/node.rb
module Capybara::Webkit
class Node < Capybara::Driver::Node
def initialize(driver, base, browser)
super(driver, base)
@browser = browser
end
def visible_text
text = invoke(:text).to_s
if Capybara::VERSION.to_f < 3.0
Capybara::Helpers.normalize_whitespace(text)
else
text.gsub(/\ +/, ' ')
.gsub(/[\ \n]*\n[\ \n]*/, "\n")
.gsub(/\A[[:space:]&&[^\u00a0]]+/, "")
.gsub(/[[:space:]&&[^\u00a0]]+\z/, "")
.tr("\u00a0", ' ')
end
end
alias_method :text, :visible_text
def all_text
text = invoke(:allText)
if Capybara::VERSION.to_f < 3.0
Capybara::Helpers.normalize_whitespace(text)
else
text.gsub(/[\u200b\u200e\u200f]/, '')
.gsub(/[\ \n\f\t\v\u2028\u2029]+/, ' ')
.gsub(/\A[[:space:]&&[^\u00a0]]+/, "")
.gsub(/[[:space:]&&[^\u00a0]]+\z/, "")
.tr("\u00a0", ' ')
end
end
def [](name)
name = name.to_s
tn = tag_name
if (tn == "img" && name == "src") || (tn == "a" && name == "href")
# Although the attribute matters, the property is consistent. Return that in
# preference to the attribute for links and images.
# if attribute exists get the property
val = invoke(:attribute, name) && invoke(:property, name)
else
val = invoke(:property, name)
val = invoke(:attribute, name) if val.nil? || val.is_a?(Hash)
end
val
end
def value
if multiple_select?
self.find_xpath(".//option").select(&:selected?).map(&:value)
else
invoke "value"
end
end
def inner_html
invoke 'getInnerHTML'
end
def inner_html=(value)
invoke 'setInnerHTML', value
end
def set(value, options = {})
warn "Options passed to Node#set but capybara-webkit doesn't currently support any - ignoring" unless options.empty?
invoke "set", *[value].flatten
end
def send_keys(*keys)
# Currently unsupported keys specified by Capybara
# :separator
invoke("sendKeys", convert_to_named_keys(keys).to_json)
end
def select_option
invoke "selectOption"
end
def unselect_option
select = find_xpath("ancestor::select").first
if select.multiple_select?
invoke "unselectOption"
else
raise Capybara::UnselectNotAllowed
end
end
def click(keys = [], offset = {})
invoke("leftClick", keys.to_json, offset.to_json)
end
def double_click(keys = [], offset = {})
invoke("doubleClick", keys.to_json, offset.to_json)
end
def right_click(keys = [], offset = {})
invoke("rightClick", keys.to_json, offset.to_json)
end
def hover
invoke("hover")
end
def drag_to(element)
invoke 'dragTo', element.native
end
def tag_name
invoke "tagName"
end
def visible?
invoke("visible") == true
end
def selected?
invoke("selected") == true
end
def checked?
!!self["checked"]
end
def disabled?
xpath = "parent::optgroup[@disabled] | " \
"ancestor::select[@disabled] | " \
"parent::fieldset[@disabled] | " \
"ancestor::*[not(self::legend) or " \
"preceding-sibling::legend][parent::fieldset[@disabled]]"
self["disabled"] || !find_xpath(xpath).empty?
end
def path
invoke "path"
end
def submit(opts = {})
invoke "submit"
end
def trigger(event)
invoke "trigger", event
end
def find_xpath(xpath)
invoke("findXpathWithin", xpath).split(',').map do |native|
self.class.new(driver, native, @browser)
end
end
alias_method :find, :find_xpath
def find_css(selector)
invoke("findCssWithin", selector).split(',').map do |native|
self.class.new(driver, native, @browser)
end
end
def invoke(name, *args)
result = @browser.command "Node", name, allow_unattached_nodes?, native, *args
JSON.parse(result, quirks_mode: true)
end
def allow_unattached_nodes?
!automatic_reload?
end
def automatic_reload?
session_option(:automatic_reload)
end
def attached?
warn "[DEPRECATION] The Capybara::Webkit::Node#attached? " \
"method is deprecated without replacement."
result = @browser.command("Node", "isAttached", native)
JSON.parse(result, quirks_mode: true)
end
def multiple_select?
self.tag_name == "select" && self["multiple"]
end
def ==(other)
invoke("equals", other.native)
end
private
def session_option(name)
if driver.respond_to?(:session_options)
driver.session_options.public_send(name)
else
Capybara.respond_to?(name) && Capybara.public_send(name)
end
end
def convert_to_named_keys(key)
if key.is_a? Array
key.map { |k| convert_to_named_keys(k)}
else
case key
when :cancel, :help, :backspace, :tab, :clear, :return, :enter, :insert, :delete, :pause, :escape,
:space, :end, :home, :left, :up, :right, :down, :semicolon,
:f1, :f2, :f3, :f4, :f5, :f6, :f7, :f8, :f9, :f10, :f11, :f12,
:shift, :control, :alt, :meta
{ "key" => key.to_s.capitalize }
when :equals
{ "key" => "Equal" }
when :page_up
{ "key" => "PageUp" }
when :page_down
{ "key" => "PageDown" }
when :numpad0, :numpad1, :numpad2, :numpad3, :numpad4,
:numpad5, :numpad6, :numpad7, :numpad8, :numpad9
{ "key" => key[-1], "modifier" => "keypad" }
when :multiply
{ "key" => "Asterisk", "modifier" => "keypad" }
when :divide
{ "key" => "Slash", "modifier" => "keypad" }
when :add
{ "key" => "Plus", "modifier" => "keypad" }
when :subtract
{ "key" => "Minus", "modifier" => "keypad" }
when :decimal
{ "key" => "Period", "modifier" => "keypad" }
when :command
{ "key" => "Meta" }
when String
key.to_s
else
raise Capybara::NotSupportedByDriverError.new
end
end
end
end
end