Class: Watir::Element

Inherits:
Object
  • Object
show all
Extended by:
AttributeHelper
Includes:
Adjacent, Container, EventuallyPresent, Exception, JSExecution, Locators::ClassHelpers, Scrolling, Waitable
Defined in:
lib/watir/elements/element.rb

Overview

Base class for HTML elements.

Direct Known Subclasses

HTMLElement

Constant Summary collapse

CASE_INSENSITIVE_ATTRIBUTES =
%i[accept accept_charset align alink axis
bgcolor charset checked clear codetype
color compact declare defer dir direction
disabled enctype face frame hreflang
http_equiv lang language link media
method multiple nohref noresize noshade
nowrap readonly rel rev rules scope
scrolling selected shape target text
type valign valuetype vlink].freeze

Instance Attribute Summary collapse

Instance Method Summary collapse

Methods included from AttributeHelper

define_attribute, define_boolean_attribute, define_float_attribute, define_int_attribute, define_string_attribute, inherit_attributes_from, method, typed_attributes

Methods included from Scrolling

#scroll

Methods included from Locators::ClassHelpers

#class_from_string, #element_class_name, #element_matcher_class, #locator, #locator_class, #selector_builder, #selector_builder_class

Methods included from JSExecution

#execute_script, #fire_event, #flash, #focus, #inner_html, #inner_text, #outer_html, #select_text, #selected_text, #text_content

Methods included from Adjacent

#child, #children, #following_sibling, #following_siblings, #parent, #preceding_sibling, #preceding_siblings, #siblings

Methods included from Waitable

#wait_until, #wait_until_present, #wait_while, #wait_while_present

Methods included from EventuallyPresent

#when_enabled, #when_present

Methods included from Container

#a, #abbr, #abbrs, #address, #addresses, #area, #areas, #article, #articles, #as, #aside, #asides, #audio, #audios, #b, #base, #bases, #bdi, #bdis, #bdo, #bdos, #blockquote, #blockquotes, #body, #bodys, #br, #brs, #bs, #button, #buttons, #canvas, #canvases, #caption, #captions, #checkbox, #checkboxes, #circle, #circles, #cite, #cites, #code, #codes, #col, #colgroup, #colgroups, #cols, #data, #datalist, #datalists, #datas, #date_field, #date_fields, #date_time_field, #date_time_fields, #dd, #dds, #defs, #defss, #del, #dels, #desc, #descs, #details, #detailses, #dfn, #dfns, #dialog, #dialogs, #div, #divs, #dl, #dls, #dt, #dts, #element, #elements, #ellipse, #ellipses, #em, #embed, #embeds, #ems, #extract_selector, #field_set, #field_sets, #fieldset, #fieldsets, #figcaption, #figcaptions, #figure, #figures, #file_field, #file_fields, #font, #fonts, #footer, #footers, #foreign_object, #foreign_objects, #form, #forms, #frame, #frames, #frameset, #framesets, #g, #gs, #h1, #h1s, #h2, #h2s, #h3, #h3s, #h4, #h4s, #h5, #h5s, #h6, #h6s, #head, #header, #headers, #heads, #hidden, #hiddens, #hr, #hrs, #html, #htmls, #i, #iframe, #iframes, #image, #images, #img, #imgs, #input, #inputs, #ins, #inses, #is, #kbd, #kbds, #label, #labels, #legend, #legends, #li, #line, #linear_gradient, #linear_gradients, #lines, #link, #links, #lis, #main, #mains, #map, #maps, #mark, #marker, #markers, #marks, #meta, #metadata, #metadatas, #metas, #meter, #meters, #nav, #navs, #noscript, #noscripts, #object, #objects, #ol, #ols, #optgroup, #optgroups, #option, #options, #output, #outputs, #p, #param, #params, #path, #paths, #pattern, #patterns, #picture, #pictures, #polygon, #polygons, #polyline, #polylines, #pre, #pres, #progress, #progresses, #ps, #q, #qs, #radial_gradient, #radial_gradients, #radio, #radio_set, #radios, #rb, #rbs, #rect, #rects, #rp, #rps, #rt, #rtc, #rtcs, #rts, #rubies, #ruby, #s, #samp, #samps, #script, #scripts, #section, #sections, #select, #select_list, #select_lists, #selects, #small, #smalls, #source, #sources, #span, #spans, #ss, #stop, #stops, #strong, #strongs, #styles, #sub, #subs, #summaries, #summary, #sup, #sups, #svg, #svgs, #switch, #switches, #symbol, #symbols, #table, #tables, #tbody, #tbodys, #td, #tds, #template, #templates, #text_field, #text_fields, #text_path, #text_paths, #textarea, #textareas, #tfoot, #tfoots, #th, #thead, #theads, #ths, #time, #times, #title, #titles, #tr, #track, #tracks, #trs, #tspan, #tspans, #u, #ul, #uls, #us, #use, #uses, #var, #vars, #video, #videos, #view, #views, #wbr, #wbrs

Methods included from JSSnippets

#execute_js

Constructor Details

#initialize(query_scope, selector) ⇒ Element

Returns a new instance of Element.

Raises:

  • (ArgumentError)

43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
# File 'lib/watir/elements/element.rb', line 43

def initialize(query_scope, selector)
  @query_scope = query_scope

  raise ArgumentError, "invalid argument: #{selector.inspect}" unless selector.is_a? Hash

  @element = selector.delete(:element)

  if @element && !(selector.keys - %i[tag_name]).empty?
    Watir.logger.deprecate(':element locator to initialize a relocatable Element', '#cache=', ids: [:element_cache])
  end

  @selector = selector

  build unless @element
end

Dynamic Method Handling

This class handles dynamic methods through the method_missing method

#method_missing(meth, *args, &blk) ⇒ Object (private)


848
849
850
851
852
853
854
855
856
857
858
859
# File 'lib/watir/elements/element.rb', line 848

def method_missing(meth, *args, &blk)
  method = meth.to_s
  if method =~ Locators::Element::SelectorBuilder::WILDCARD_ATTRIBUTE
    attribute_value(meth, *args)
  elsif UserEditable.instance_methods(false).include?(meth) && content_editable?
    @content_editable = true
    extend UserEditable
    send(meth, *args, &blk)
  else
    super
  end
end

Instance Attribute Details

#keywordObject

Returns the value of attribute keyword


18
19
20
# File 'lib/watir/elements/element.rb', line 18

def keyword
  @keyword
end

#selectorObject (readonly)

Returns the value of attribute selector


19
20
21
# File 'lib/watir/elements/element.rb', line 19

def selector
  @selector
end

Instance Method Details

#==(other) ⇒ Object Also known as: eql?

Returns true if two elements are equal.

TODO: Address how this is affected by stale elements TODO: Address how this is affected by HTMLElement vs subclass TODO: Address how this is affected by a non-located element

Examples:

browser.text_field(name: "new_user_first_name") == browser.text_field(name: "new_user_first_name")
#=> true

105
106
107
# File 'lib/watir/elements/element.rb', line 105

def ==(other)
  other.is_a?(self.class) && wd == other.wd
end

#attribute_listArray

Returns list of all attributes. Attributes with special characters are returned as String, rest are returned as a Symbol.

Examples:

browser.pre(id: 'rspec').attribute_list
#=> [:class, :id]

Returns:

  • (Array)

351
352
353
# File 'lib/watir/elements/element.rb', line 351

def attribute_list
  attribute_values.keys
end

#attribute_value(attribute_name) ⇒ String? Also known as: attribute

Returns given attribute value of element.

Examples:

browser.a(id: "link_2").attribute_value "title"
#=> "link_title_2"

Parameters:

  • attribute_name (String, ::Symbol)

Returns:

  • (String, nil)

312
313
314
315
# File 'lib/watir/elements/element.rb', line 312

def attribute_value(attribute_name)
  attribute_name = attribute_name.to_s.tr('_', '-') if attribute_name.is_a?(::Symbol)
  element_call { @element.attribute attribute_name }
end

#attribute_valuesHash Also known as: attributes

Returns all attribute values. Attributes with special characters are returned as String, rest are returned as a Symbol.

Examples:

browser.pre(id: 'rspec').attribute_values
#=> {class:'ruby', id: 'rspec' }

Returns:

  • (Hash)

329
330
331
332
333
334
335
336
337
# File 'lib/watir/elements/element.rb', line 329

def attribute_values
  result = element_call { execute_js(:attributeValues, @element) }
  result.keys.each do |key|
    next unless key == key[/[a-zA-Z\-]*/]

    result[key.tr('-', '_').to_sym] = result.delete(key)
  end
  result
end

#browserWatir::Browser

Returns browser.

Returns:


590
591
592
# File 'lib/watir/elements/element.rb', line 590

def browser
  @query_scope.browser
end

#buildObject

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.


633
634
635
# File 'lib/watir/elements/element.rb', line 633

def build
  selector_builder.build(@selector.dup)
end

#cache=(element) ⇒ 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.

Set the cached element. For use when element can be relocated with the provided selector.


655
656
657
# File 'lib/watir/elements/element.rb', line 655

def cache=(element)
  @element = element
end

#centerSelenium::WebDriver::Point Also known as: centre

Get centre coordinates of element

Examples:

browser.button(name: "new_user_button").centre

Returns:

  • (Selenium::WebDriver::Point)

454
455
456
457
458
459
# File 'lib/watir/elements/element.rb', line 454

def center
  point = location
  dimensions = size
  Selenium::WebDriver::Point.new(point.x + (dimensions['width'] / 2),
                                 point.y + (dimensions['height'] / 2))
end

#class_nameString

Returns value of className property.

Returns:

  • (String)

    value of className property


41
# File 'lib/watir/elements/element.rb', line 41

attribute String, :class_name, :className

#classesArray

Returns list of class values.

Returns:

  • (Array)

297
298
299
# File 'lib/watir/elements/element.rb', line 297

def classes
  class_name.split
end

#click(*modifiers) ⇒ Object

Clicks the element, optionally while pressing the given modifier keys. Note that support for holding a modifier key is currently experimental, and may not work at all.

Examples:

Click an element

browser.element(name: "new_user_button").click

Click an element with shift key pressed

browser.element(name: "new_user_button").click(:shift)

Click an element with several modifier keys pressed

browser.element(name: "new_user_button").click(:shift, :control)

Parameters:

  • modifiers (:shift, :alt, :control, :command, :meta)

    to press while clicking.


151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
# File 'lib/watir/elements/element.rb', line 151

def click(*modifiers)
  element_call(:wait_for_enabled) do
    if modifiers.any?
      action = driver.action
      modifiers.each { |mod| action.key_down mod }
      action.click @element
      modifiers.each { |mod| action.key_up mod }

      action.perform
    else
      @element.click
    end
  end

  browser.after_hooks.run
end

#click!Object

Simulates JavaScript click event on element.

Examples:

Click an element

browser.element(name: "new_user_button").click!

175
176
177
178
# File 'lib/watir/elements/element.rb', line 175

def click!
  fire_event :click
  browser.after_hooks.run
end

#double_clickObject

Double clicks the element. Note that browser support may vary.

Examples:

browser.element(name: "new_user_button").double_click

188
189
190
191
# File 'lib/watir/elements/element.rb', line 188

def double_click
  element_call(:wait_for_present) { driver.action.double_click(@element).perform }
  browser.after_hooks.run
end

#double_click!Object

Simulates JavaScript double click event on element.

Examples:

browser.element(name: "new_user_button").double_click!

200
201
202
203
# File 'lib/watir/elements/element.rb', line 200

def double_click!
  fire_event :dblclick
  browser.after_hooks.run
end

#drag_and_drop_by(right_by, down_by) ⇒ Object

Drag and drop this element by the given offsets. Note that browser support may vary.

Examples:

browser.div(id: "draggable").drag_and_drop_by 100, 25

Parameters:

  • right_by (Integer)
  • down_by (Integer)

283
284
285
286
287
288
289
# File 'lib/watir/elements/element.rb', line 283

def drag_and_drop_by(right_by, down_by)
  element_call(:wait_for_present) do
    driver.action
          .drag_and_drop_by(@element, right_by, down_by)
          .perform
  end
end

#drag_and_drop_on(other) ⇒ Object

Drag and drop this element on to another element instance. Note that browser support may vary.

Examples:

a = browser.div(id: "draggable")
b = browser.div(id: "droppable")
a.drag_and_drop_on b

260
261
262
263
264
265
266
267
268
269
270
# File 'lib/watir/elements/element.rb', line 260

def drag_and_drop_on(other)
  assert_is_element other

  value = element_call(:wait_for_present) do
    driver.action
          .drag_and_drop(@element, other.wd)
          .perform
  end
  browser.after_hooks.run
  value
end

#driverObject

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.


466
467
468
# File 'lib/watir/elements/element.rb', line 466

def driver
  @query_scope.driver
end

#enabled?Boolean

Returns true if this element is present and enabled on the page.

Returns:

  • (Boolean)

See Also:


502
503
504
# File 'lib/watir/elements/element.rb', line 502

def enabled?
  element_call(:assert_exists) { @element.enabled? }
end

#exists?Boolean Also known as: exist?

Returns true if element exists. Checking for staleness is deprecated

Returns:

  • (Boolean)

66
67
68
69
70
71
72
73
74
75
76
77
# File 'lib/watir/elements/element.rb', line 66

def exists?
  if located? && stale?
    reset!
  elsif located?
    return true
  end

  assert_exists
  true
rescue UnknownObjectException, UnknownFrameException
  false
end

#focused?Boolean

Returns true if this element is focused.

Returns:

  • (Boolean)

374
375
376
# File 'lib/watir/elements/element.rb', line 374

def focused?
  element_call { @element == driver.switch_to.active_element }
end

#hashObject


110
111
112
# File 'lib/watir/elements/element.rb', line 110

def hash
  located? ? @element.hash : super
end

#heightSelenium::WebDriver::Dimension

Get height of element

Examples:

browser.button(name: "new_user_button").height

Returns:

  • (Selenium::WebDriver::Dimension)

428
429
430
# File 'lib/watir/elements/element.rb', line 428

def height
  size['height']
end

#hoverObject

Moves the mouse to the middle of this element. Note that browser support may vary.

Examples:

browser.element(name: "new_user_button").hover

246
247
248
# File 'lib/watir/elements/element.rb', line 246

def hover
  element_call(:wait_for_present) { driver.action.move_to(@element).perform }
end

#idString

temporarily add :id and :class_name manually since they're no longer specified in the HTML spec.

TODO: use IDL from DOM core - dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html

Returns:

  • (String)

    value of id property

See Also:


40
# File 'lib/watir/elements/element.rb', line 40

attribute String, :id, :id

#inspectObject


80
81
82
83
84
85
86
87
88
89
90
91
# File 'lib/watir/elements/element.rb', line 80

def inspect
  string = "#<#{self.class}: "
  string << "keyword: #{keyword} " if keyword
  string << "located: #{located?}; "
  string << if @selector.empty?
              '{element: (selenium element)}'
            else
              selector_string
            end
  string << '>'
  string
end

#locateObject

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.


623
624
625
626
627
# File 'lib/watir/elements/element.rb', line 623

def locate
  ensure_context
  locate_in_context
  self
end

#located?Boolean

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.

Returns true if element has been previously located.

Returns:

  • (Boolean)

645
646
647
# File 'lib/watir/elements/element.rb', line 645

def located?
  !!@element
end

#locationSelenium::WebDriver::Point

location of element (x, y)

Examples:

browser.button(name: "new_user_button").location

Returns:

  • (Selenium::WebDriver::Point)

402
403
404
# File 'lib/watir/elements/element.rb', line 402

def location
  element_call { @element.location }
end

#obscured?Boolean

Returns true if the element's center point is covered by a non-descendant element.

Returns:

  • (Boolean)

526
527
528
529
530
531
532
533
# File 'lib/watir/elements/element.rb', line 526

def obscured?
  element_call do
    return true unless present?

    scroll.to
    execute_js(:elementObscured, self)
  end
end

#present?Boolean

Returns true if the element exists and is visible on the page. Returns false if element does not exist or exists but is not visible

Returns:

  • (Boolean)

See Also:


514
515
516
517
518
# File 'lib/watir/elements/element.rb', line 514

def present?
  display_check
rescue UnknownObjectException, UnknownFrameException
  false
end

#reset!Object


615
616
617
# File 'lib/watir/elements/element.rb', line 615

def reset!
  @element = nil
end

#right_click(*modifiers) ⇒ Object

Right clicks the element, optionally while pressing the given modifier keys. Note that support for holding a modifier key is currently experimental, and may not work at all. Also, the browser support may vary.

Examples:

browser.element(name: "new_user_button").right_click

Right click an element with shift key pressed

browser.element(name: "new_user_button").right_click(:shift)

Click an element with several modifier keys pressed

browser.element(name: "new_user_button").right_click(:shift, :alt)

Parameters:

  • modifiers (:shift, :alt, :control, :command, :meta)

    to press while right clicking.


222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
# File 'lib/watir/elements/element.rb', line 222

def right_click(*modifiers)
  element_call(:wait_for_present) do
    action = driver.action
    if modifiers.any?
      modifiers.each { |mod| action.key_down mod }
      action.context_click(@element)
      modifiers.each { |mod| action.key_up mod }
      action.perform
    else
      action.context_click(@element).perform
    end
  end

  browser.after_hooks.run
end

#scroll_into_viewSelenium::WebDriver::Point

Scroll until the element is in the view screen

Examples:

browser.button(name: "new_user_button").scroll_into_view

Returns:

  • (Selenium::WebDriver::Point)

387
388
389
390
391
# File 'lib/watir/elements/element.rb', line 387

def scroll_into_view
  Watir.logger.deprecate 'Element#scroll_into_view', 'Element#scroll methods', ids: [:scroll_into_view]

  element_call { @element.location_once_scrolled_into_view }
end

#selector_stringObject

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.


663
664
665
666
667
# File 'lib/watir/elements/element.rb', line 663

def selector_string
  return @selector.inspect if @query_scope.is_a?(Browser)

  "#{@query_scope.selector_string} --> #{@selector.inspect}"
end

#send_keys(*args) ⇒ Object

Sends sequence of keystrokes to element.

Examples:

browser.text_field(name: "new_user_first_name").send_keys "Watir", :return

Parameters:


364
365
366
# File 'lib/watir/elements/element.rb', line 364

def send_keys(*args)
  element_call(:wait_for_writable) { @element.send_keys(*args) }
end

#sizeSelenium::WebDriver::Dimension

size of element (width, height)

Examples:

browser.button(name: "new_user_button").size

Returns:

  • (Selenium::WebDriver::Dimension)

415
416
417
# File 'lib/watir/elements/element.rb', line 415

def size
  element_call { @element.size }
end

#stale?Boolean

Returns true if a previously located element is no longer attached to DOM.

Returns:

  • (Boolean)

Raises:

See Also:


601
602
603
604
605
606
# File 'lib/watir/elements/element.rb', line 601

def stale?
  raise Error, 'Can not check staleness of unused element' unless @element

  ensure_context
  stale_in_context?
end

#stale_in_context?Boolean

Returns:

  • (Boolean)

608
609
610
611
612
613
# File 'lib/watir/elements/element.rb', line 608

def stale_in_context?
  @element.css_value('staleness_check') # any wire call will check for staleness
  false
rescue Selenium::WebDriver::Error::StaleElementReferenceError
  true
end

#style(property = nil) ⇒ String

Returns given style property of this element.

Examples:

browser.button(value: "Delete").style           #=> "border: 4px solid red;"
browser.button(value: "Delete").style("border") #=> "4px solid rgb(255, 0, 0)"

Parameters:

  • property (String) (defaults to: nil)

Returns:

  • (String)

546
547
548
549
550
551
552
# File 'lib/watir/elements/element.rb', line 546

def style(property = nil)
  if property
    element_call { @element.style property }
  else
    attribute_value('style').to_s.strip
  end
end

#tag_nameString

Returns tag name of the element.

Returns:

  • (String)

130
131
132
# File 'lib/watir/elements/element.rb', line 130

def tag_name
  element_call { @element.tag_name.downcase }
end

#textString

Returns the text of the element.

Returns:

  • (String)

120
121
122
# File 'lib/watir/elements/element.rb', line 120

def text
  element_call { @element.text }
end

#to_subtypeObject

Cast this Element instance to a more specific subtype.

Examples:

browser.element(xpath: "//input[@type='submit']").to_subtype
#=> #<Watir::Button>

562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
# File 'lib/watir/elements/element.rb', line 562

def to_subtype
  tag = tag_name
  klass = if tag == 'input'
            case attribute_value(:type)
            when 'checkbox'
              CheckBox
            when 'radio'
              Radio
            when 'file'
              FileField
            when *Button::VALID_TYPES
              Button
            else
              TextField
            end
          else
            Watir.element_class_for(tag)
          end

  klass.new(@query_scope, @selector).tap { |el| el.cache = wd }
end

#visible?Boolean

Returns true if this element is visible on the page. Raises exception if element does not exist

Returns:

  • (Boolean)

488
489
490
491
492
493
# File 'lib/watir/elements/element.rb', line 488

def visible?
  msg = '#visible? behavior will be changing slightly, consider switching to #present? ' \
        '(more details: http://watir.com/element-existentialism/)'
  Watir.logger.warn msg, ids: [:visible_element]
  display_check
end

#wdSelenium::WebDriver::Element

Returns underlying Selenium object of the Watir Element

Returns:

  • (Selenium::WebDriver::Element)

476
477
478
479
# File 'lib/watir/elements/element.rb', line 476

def wd
  assert_exists
  @element
end

#widthSelenium::WebDriver::Dimension

Get width of element

Examples:

browser.button(name: "new_user_button").width

Returns:

  • (Selenium::WebDriver::Dimension)

441
442
443
# File 'lib/watir/elements/element.rb', line 441

def width
  size['width']
end