Class: Capybara::Node::Element
- Defined in:
- lib/capybara/node/element.rb
Overview
A Element represents a single element on the page. It is possible to interact with the contents of this element the same as with a document:
session = ::Session.new(:rack_test, my_app)
= session.find('#bar') # from Capybara::Node::Finders
.select('Baz', from: 'Quox') # from Capybara::Node::Actions
Element also has access to HTML attributes and other properties of the element:
.value
.text
[:title]
Constant Summary collapse
- STYLE_SCRIPT =
<<~JS (function(){ var s = window.getComputedStyle(this); var result = {}; for (var i = arguments.length; i--; ) { var property_name = arguments[i]; result[property_name] = s.getPropertyValue(property_name); } return result; }).apply(this, arguments) JS
Instance Attribute Summary
Attributes inherited from Base
Instance Method Summary collapse
-
#[](attribute) ⇒ String
Retrieve the given attribute.
- #allow_reload! ⇒ Object
-
#checked? ⇒ Boolean
Whether or not the element is checked.
-
#click(*modifier_keys, wait: nil, **offset) ⇒ Capybara::Node::Element
Click the Element.
-
#disabled? ⇒ Boolean
Whether or not the element is disabled.
-
#double_click(*modifier_keys, wait: nil, **offset) ⇒ Capybara::Node::Element
Double Click the Element.
-
#drag_to(node, **options) ⇒ Capybara::Node::Element
Drag the element to the given other element.
-
#drop(*args) ⇒ Capybara::Node::Element
Drop items on the current element.
-
#evaluate_async_script(script, *args) ⇒ Object
Evaluate the given JavaScript in the context of the element and obtain the result from a callback function which will be passed as the last argument to the script.
-
#evaluate_script(script, *args) ⇒ Object
Evaluate the given JS in the context of the element and return the result.
-
#execute_script(script, *args) ⇒ Object
Execute the given JS in the context of the element not returning a result.
-
#flash ⇒ Capybara::Node::Element
Toggle the elements background color between white and black for a period of time.
-
#hover ⇒ Capybara::Node::Element
Hover on the Element.
- #initial_cache ⇒ Object private
-
#initialize(session, base, query_scope, query) ⇒ Element
constructor
A new instance of Element.
-
#inspect ⇒ String
A human-readable representation of the element.
-
#multiple? ⇒ Boolean
Whether or not the element supports multiple results.
-
#native ⇒ Object
The native element from the driver, this allows access to driver specific methods.
-
#obscured? ⇒ Boolean
Whether or not the element is currently in the viewport and it (or descendants) would be considered clickable at the elements center point.
-
#path ⇒ String
An XPath expression describing where on the page the element can be found.
-
#readonly? ⇒ Boolean
Whether or not the element is readonly.
- #rect ⇒ Object
- #reload ⇒ Object private
-
#right_click(*modifier_keys, wait: nil, **offset) ⇒ Capybara::Node::Element
Right Click the Element.
-
#scroll_to(pos_or_el_or_x, y = nil, align: :top, offset: nil) ⇒ Capybara::Node::Element
Scroll the page or element.
-
#select_option(wait: nil) ⇒ Capybara::Node::Element
Select this node if it is an option element inside a select tag.
-
#selected? ⇒ Boolean
Whether or not the element is selected.
-
#send_keys(keys, ...) ⇒ Capybara::Node::Element
Send Keystrokes to the Element.
-
#set(value, **options) ⇒ Capybara::Node::Element
Set the value of the form element to the given value.
-
#style(*styles) ⇒ Hash
Retrieve the given CSS styles.
-
#tag_name ⇒ String
The tag name of the element.
-
#text(type = nil, normalize_ws: false) ⇒ String
Retrieve the text of the element.
-
#trigger(event) ⇒ Capybara::Node::Element
Trigger any event on the current element, for example mouseover or focus events.
-
#unselect_option(wait: nil) ⇒ Capybara::Node::Element
Unselect this node if it is an option element inside a multiple select tag.
-
#value ⇒ String
The value of the form element.
-
#visible? ⇒ Boolean
Whether or not the element is visible.
Methods inherited from Base
#find_css, #find_xpath, #session_options, #synchronize, #to_capybara_node
Methods included from Minitest::Expectations
Methods included from Matchers
#==, #assert_all_of_selectors, #assert_ancestor, #assert_any_of_selectors, #assert_matches_selector, #assert_matches_style, #assert_no_ancestor, #assert_no_selector, #assert_no_sibling, #assert_no_text, #assert_none_of_selectors, #assert_not_matches_selector, #assert_selector, #assert_sibling, #assert_style, #assert_text, #has_ancestor?, #has_button?, #has_checked_field?, #has_css?, #has_field?, #has_link?, #has_no_ancestor?, #has_no_button?, #has_no_checked_field?, #has_no_css?, #has_no_field?, #has_no_link?, #has_no_select?, #has_no_selector?, #has_no_sibling?, #has_no_table?, #has_no_text?, #has_no_unchecked_field?, #has_no_xpath?, #has_select?, #has_selector?, #has_sibling?, #has_style?, #has_table?, #has_text?, #has_unchecked_field?, #has_xpath?, #matches_css?, #matches_selector?, #matches_style?, #matches_xpath?, #not_matches_css?, #not_matches_selector?, #not_matches_xpath?
Methods included from Actions
#attach_file, #check, #choose, #click_button, #click_link, #click_link_or_button, #fill_in, #select, #uncheck, #unselect
Methods included from Finders
#all, #ancestor, #find, #find_button, #find_by_id, #find_field, #find_link, #first, #sibling
Constructor Details
#initialize(session, base, query_scope, query) ⇒ Element
25 26 27 28 29 30 |
# File 'lib/capybara/node/element.rb', line 25 def initialize(session, base, query_scope, query) super(session, base) @query_scope = query_scope @query = query @allow_reload = false end |
Instance Method Details
#[](attribute) ⇒ String
Retrieve the given attribute.
element[:title] # => HTML title attribute
71 72 73 |
# File 'lib/capybara/node/element.rb', line 71 def [](attribute) synchronize { base[attribute] } end |
#allow_reload! ⇒ Object
32 33 34 |
# File 'lib/capybara/node/element.rb', line 32 def allow_reload! @allow_reload = true end |
#checked? ⇒ Boolean
Whether or not the element is checked.
322 323 324 |
# File 'lib/capybara/node/element.rb', line 322 def checked? synchronize { base.checked? } end |
#click(*modifier_keys, wait: nil, **offset) ⇒ Capybara::Node::Element
Click the Element.
If the driver dynamic pages (JS) and the element is currently non-interactable, this method will continuously retry the action until either the element becomes interactable or the maximum wait time expires.
Both x: and y: must be specified if an offset is wanted, if not specified the click will occur at the middle of the element.
167 168 169 170 171 |
# File 'lib/capybara/node/element.rb', line 167 def click(*keys, **) perform_click_action(keys, ) do |k, opts| base.click(k, opts) end end |
#disabled? ⇒ Boolean
Whether or not the element is disabled.
342 343 344 |
# File 'lib/capybara/node/element.rb', line 342 def disabled? synchronize { base.disabled? } end |
#double_click(*modifier_keys, wait: nil, **offset) ⇒ Capybara::Node::Element
Double Click the Element.
If the driver dynamic pages (JS) and the element is currently non-interactable, this method will continuously retry the action until either the element becomes interactable or the maximum wait time expires.
Both x: and y: must be specified if an offset is wanted, if not specified the click will occur at the middle of the element.
193 194 195 196 197 |
# File 'lib/capybara/node/element.rb', line 193 def double_click(*keys, **) perform_click_action(keys, ) do |k, opts| base.double_click(k, opts) end end |
#drag_to(node, **options) ⇒ Capybara::Node::Element
Drag the element to the given other element.
source = page.find('#foo')
target = page.find('#bar')
source.drag_to(target)
412 413 414 415 |
# File 'lib/capybara/node/element.rb', line 412 def drag_to(node, **) synchronize { base.drag_to(node.base, **) } self end |
#drop(path, ...) ⇒ Capybara::Node::Element #drop(strings, ...) ⇒ Capybara::Node::Element
Drop items on the current element.
target = page.find('#foo')
target.drop('/some/path/file.csv')
431 432 433 434 435 436 437 438 439 |
# File 'lib/capybara/node/element.rb', line 431 def drop(*args) = args.map do |arg| return arg.to_path if arg.respond_to?(:to_path) arg end synchronize { base.drop(*) } self end |
#evaluate_async_script(script, *args) ⇒ Object
Evaluate the given JavaScript in the context of the element and obtain the result from a
callback function which will be passed as the last argument to the script. this
in the
script will refer to the element this is called on.
516 517 518 519 520 521 522 |
# File 'lib/capybara/node/element.rb', line 516 def evaluate_async_script(script, *args) session.evaluate_async_script(<<~JS, self, *args) (function (){ #{script} }).apply(arguments[0], Array.prototype.slice.call(arguments,1)); JS end |
#evaluate_script(script, *args) ⇒ Object
Evaluate the given JS in the context of the element and return the result. Be careful when using this with
scripts that return complex objects, such as jQuery statements. #execute_script might
be a better alternative. this
in the script will refer to the element this is called on.
499 500 501 502 503 504 505 |
# File 'lib/capybara/node/element.rb', line 499 def evaluate_script(script, *args) session.evaluate_script(<<~JS, self, *args) (function(){ return #{script.strip} }).apply(arguments[0], Array.prototype.slice.call(arguments,1)); JS end |
#execute_script(script, *args) ⇒ Object
Execute the given JS in the context of the element not returning a result. This is useful for scripts that return
complex objects, such as jQuery statements. #execute_script should be used over
#evaluate_script whenever a result is not expected or needed. this
in the script will refer to the element this is called on.
482 483 484 485 486 487 488 |
# File 'lib/capybara/node/element.rb', line 482 def execute_script(script, *args) session.execute_script(<<~JS, self, *args) (function (){ #{script} }).apply(arguments[0], Array.prototype.slice.call(arguments,1)); JS end |
#flash ⇒ Capybara::Node::Element
Toggle the elements background color between white and black for a period of time.
529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 |
# File 'lib/capybara/node/element.rb', line 529 def flash execute_script(<<~JS, 100) async function flash(el, delay){ var old_bg = el.style.backgroundColor; var colors = ["black", "white"]; for(var i=0; i<20; i++){ el.style.backgroundColor = colors[i % colors.length]; await new Promise(resolve => setTimeout(resolve, delay)); } el.style.backgroundColor = old_bg; } flash(this, arguments[0]); JS self end |
#hover ⇒ Capybara::Node::Element
Hover on the Element.
280 281 282 283 |
# File 'lib/capybara/node/element.rb', line 280 def hover synchronize { base.hover } self end |
#initial_cache ⇒ Object
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
574 575 576 |
# File 'lib/capybara/node/element.rb', line 574 def initial_cache base.respond_to?(:initial_cache) ? base.initial_cache : {} end |
#inspect ⇒ String
A human-readable representation of the element.
565 566 567 568 569 570 571 |
# File 'lib/capybara/node/element.rb', line 565 def inspect %(#<Capybara::Node::Element tag="#{base.tag_name}" path="#{base.path}">) rescue NotSupportedByDriverError %(#<Capybara::Node::Element tag="#{base.tag_name}">) rescue *session.driver.invalid_element_errors %(Obsolete #<Capybara::Node::Element>) end |
#multiple? ⇒ Boolean
Whether or not the element supports multiple results.
362 363 364 |
# File 'lib/capybara/node/element.rb', line 362 def multiple? synchronize { base.multiple? } end |
#native ⇒ Object
40 41 42 |
# File 'lib/capybara/node/element.rb', line 40 def native synchronize { base.native } end |
#obscured? ⇒ Boolean
Whether or not the element is currently in the viewport and it (or descendants) would be considered clickable at the elements center point.
312 313 314 |
# File 'lib/capybara/node/element.rb', line 312 def obscured? synchronize { base.obscured? } end |
#path ⇒ String
An XPath expression describing where on the page the element can be found.
372 373 374 |
# File 'lib/capybara/node/element.rb', line 372 def path synchronize { base.path } end |
#readonly? ⇒ Boolean
Whether or not the element is readonly.
352 353 354 |
# File 'lib/capybara/node/element.rb', line 352 def readonly? synchronize { base.readonly? } end |
#rect ⇒ Object
376 377 378 |
# File 'lib/capybara/node/element.rb', line 376 def rect synchronize { base.rect } end |
#reload ⇒ Object
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
547 548 549 550 551 552 553 554 555 556 557 558 |
# File 'lib/capybara/node/element.rb', line 547 def reload if @allow_reload begin reloaded = @query.resolve_for(query_scope.reload)&.first @base = reloaded.base if reloaded rescue StandardError => e raise e unless catch_error?(e) end end self end |
#right_click(*modifier_keys, wait: nil, **offset) ⇒ Capybara::Node::Element
Right Click the Element.
If the driver dynamic pages (JS) and the element is currently non-interactable, this method will continuously retry the action until either the element becomes interactable or the maximum wait time expires.
Both x: and y: must be specified if an offset is wanted, if not specified the click will occur at the middle of the element.
180 181 182 183 184 |
# File 'lib/capybara/node/element.rb', line 180 def right_click(*keys, **) perform_click_action(keys, ) do |k, opts| base.right_click(k, opts) end end |
#scroll_to(position, offset: [0,0]) ⇒ Capybara::Node::Element #scroll_to(element, align: :top) ⇒ Capybara::Node::Element #scroll_to(x, y) ⇒ Capybara::Node::Element
Scroll the page or element.
460 461 462 463 464 465 466 467 468 469 470 471 |
# File 'lib/capybara/node/element.rb', line 460 def scroll_to(pos_or_el_or_x, y = nil, align: :top, offset: nil) case pos_or_el_or_x when Symbol synchronize { base.scroll_to(nil, pos_or_el_or_x) } unless pos_or_el_or_x == :current when ::Node::Element synchronize { base.scroll_to(pos_or_el_or_x.base, align) } else synchronize { base.scroll_to(nil, nil, [pos_or_el_or_x, y]) } end synchronize { base.scroll_by(*offset) } unless offset.nil? self end |
#select_option(wait: nil) ⇒ Capybara::Node::Element
Select this node if it is an option element inside a select tag.
If the driver dynamic pages (JS) and the element is currently non-interactable, this method will continuously retry the action until either the element becomes interactable or the maximum wait time expires.
137 138 139 140 |
# File 'lib/capybara/node/element.rb', line 137 def select_option(wait: nil) synchronize(wait) { base.select_option } self end |
#selected? ⇒ Boolean
Whether or not the element is selected.
332 333 334 |
# File 'lib/capybara/node/element.rb', line 332 def selected? synchronize { base.selected? } end |
#send_keys(keys, ...) ⇒ Capybara::Node::Element
Send Keystrokes to the Element.
Examples:
element.send_keys "foo" #=> value: 'foo'
element.send_keys "tet", :left, "s" #=> value: 'test'
element.send_keys [:control, 'a'], :space #=> value: ' ' - assuming ctrl-a selects all contents
Symbols supported for keys:
- :cancel
- :help
- :backspace
- :tab
- :clear
- :return
- :enter
- :shift
- :control
- :alt
- :pause
- :escape
- :space
- :page_up
- :page_down
- :end
- :home
- :left
- :up
- :right
- :down
- :insert
- :delete
- :semicolon
- :equals
- :numpad0
- :numpad1
- :numpad2
- :numpad3
- :numpad4
- :numpad5
- :numpad6
- :numpad7
- :numpad8
- :numpad9
- :multiply - numeric keypad *
- :add - numeric keypad +
- :separator - numeric keypad 'separator' key ??
- :subtract - numeric keypad -
- :decimal - numeric keypad .
- :divide - numeric keypad /
- :f1
- :f2
- :f3
- :f4
- :f5
- :f6
- :f7
- :f8
- :f9
- :f10
- :f11
- :f12
- :meta
- :command - alias of :meta
270 271 272 273 |
# File 'lib/capybara/node/element.rb', line 270 def send_keys(*args) synchronize { base.send_keys(*args) } self end |
#set(value, **options) ⇒ Capybara::Node::Element
Set the value of the form element to the given value.
115 116 117 118 119 120 121 122 123 |
# File 'lib/capybara/node/element.rb', line 115 def set(value, **) if ENV['CAPYBARA_THOROUGH'] && readonly? raise ::ReadOnlyElementError, "Attempt to set readonly element with value: #{value}" end = ..to_h.merge() synchronize { base.set(value, ) } self end |
#style(*styles) ⇒ Hash
Retrieve the given CSS styles.
element.style('color', 'font-size') # => Computed values of CSS 'color' and 'font-size' styles
84 85 86 87 88 89 90 91 92 93 94 95 96 97 |
# File 'lib/capybara/node/element.rb', line 84 def style(*styles) styles = styles.flatten.map(&:to_s) raise ArgumentError, 'You must specify at least one CSS style' if styles.empty? begin synchronize { base.style(styles) } rescue NotImplementedError => e begin evaluate_script(STYLE_SCRIPT, *styles) rescue ::NotSupportedByDriverError raise e end end end |
#tag_name ⇒ String
289 290 291 292 |
# File 'lib/capybara/node/element.rb', line 289 def tag_name # Element type is immutable so cache it @tag_name ||= initial_cache[:tag_name] || synchronize { base.tag_name } end |
#text(type = nil, normalize_ws: false) ⇒ String
Retrieve the text of the element. If ignore_hidden_elements
is true
, which it is by default, then this will return only text
which is visible. The exact semantics of this may differ between
drivers, but generally any text within elements with display:none
is
ignored. This behaviour can be overridden by passing :all
to this
method.
56 57 58 59 60 |
# File 'lib/capybara/node/element.rb', line 56 def text(type = nil, normalize_ws: false) type ||= :all unless .ignore_hidden_elements || .visible_text_only txt = synchronize { type == :all ? base.all_text : base.visible_text } normalize_ws ? txt.gsub(/[[:space:]]+/, ' ').strip : txt end |
#trigger(event) ⇒ Capybara::Node::Element
Trigger any event on the current element, for example mouseover or focus events. Not supported with the Selenium driver, and SHOULDN'T BE USED IN TESTING unless you fully understand why you're using it, that it can allow actions a user could never perform, and that it may completely invalidate your test.
390 391 392 393 |
# File 'lib/capybara/node/element.rb', line 390 def trigger(event) synchronize { base.trigger(event) } self end |
#unselect_option(wait: nil) ⇒ Capybara::Node::Element
Unselect this node if it is an option element inside a multiple select tag.
If the driver dynamic pages (JS) and the element is currently non-interactable, this method will continuously retry the action until either the element becomes interactable or the maximum wait time expires.
148 149 150 151 |
# File 'lib/capybara/node/element.rb', line 148 def unselect_option(wait: nil) synchronize(wait) { base.unselect_option } self end |
#value ⇒ String
103 104 105 |
# File 'lib/capybara/node/element.rb', line 103 def value synchronize { base.value } end |
#visible? ⇒ Boolean
Whether or not the element is visible. Not all drivers support CSS, so the result may be inaccurate.
301 302 303 |
# File 'lib/capybara/node/element.rb', line 301 def visible? synchronize { base.visible? } end |