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

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)

32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
# File 'lib/watir/elements/element.rb', line 32

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)


835
836
837
838
839
840
841
842
843
844
845
846
# File 'lib/watir/elements/element.rb', line 835

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

97
98
99
# File 'lib/watir/elements/element.rb', line 97

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)

324
325
326
# File 'lib/watir/elements/element.rb', line 324

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)

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

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)

302
303
304
305
306
307
308
309
310
# File 'lib/watir/elements/element.rb', line 302

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:


577
578
579
# File 'lib/watir/elements/element.rb', line 577

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.


620
621
622
# File 'lib/watir/elements/element.rb', line 620

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.


642
643
644
# File 'lib/watir/elements/element.rb', line 642

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)

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

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


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

attribute String, :class_name, :className

#classesArray

Returns list of class values.

Returns:

  • (Array)

270
271
272
# File 'lib/watir/elements/element.rb', line 270

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.


143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
# File 'lib/watir/elements/element.rb', line 143

def click(*modifiers)
  # TODO: Should wait_for_enabled be default, or `Button` specific behavior?
  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!

168
169
170
171
# File 'lib/watir/elements/element.rb', line 168

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

181
182
183
184
# File 'lib/watir/elements/element.rb', line 181

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!

193
194
195
196
# File 'lib/watir/elements/element.rb', line 193

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, -200

Parameters:

  • right_by (Integer)
  • down_by (Integer)

256
257
258
259
260
261
262
# File 'lib/watir/elements/element.rb', line 256

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

233
234
235
236
237
238
239
240
241
242
243
# File 'lib/watir/elements/element.rb', line 233

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.


437
438
439
# File 'lib/watir/elements/element.rb', line 437

def driver
  @query_scope.driver
end

#enabled?Boolean

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

Returns:

  • (Boolean)

See Also:


482
483
484
# File 'lib/watir/elements/element.rb', line 482

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)

55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
# File 'lib/watir/elements/element.rb', line 55

def exists?
  if located? && stale?
    Watir.logger.deprecate 'Checking `#exists? == false` to determine a stale element',
                           '`#stale? == true`',
                           reference: 'http://watir.com/staleness-changes',
                           ids: [:stale_exists]    # TODO: Change this to `reset!` after removing deprecation

    return false
  end

  assert_exists
  true
rescue UnknownObjectException, UnknownFrameException
  false
end

#focused?Boolean

Returns true if this element is focused.

Returns:

  • (Boolean)

347
348
349
# File 'lib/watir/elements/element.rb', line 347

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

#hashObject


102
103
104
# File 'lib/watir/elements/element.rb', line 102

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)

399
400
401
# File 'lib/watir/elements/element.rb', line 399

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

219
220
221
# File 'lib/watir/elements/element.rb', line 219

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:


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

attribute String, :id, :id

#inspectObject


72
73
74
75
76
77
78
79
80
81
82
83
# File 'lib/watir/elements/element.rb', line 72

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.


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

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)

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

def located?
  !!@element
end

#locationSelenium::WebDriver::Point

location of element (x, y)

Examples:

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

Returns:

  • (Selenium::WebDriver::Point)

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

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)

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

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:


494
495
496
497
498
499
500
501
502
503
504
505
# File 'lib/watir/elements/element.rb', line 494

def present?
  displayed = display_check
  if displayed.nil? && display_check
    Watir.logger.deprecate 'Checking `#present? == false` to determine a stale element',
                           '`#stale? == true`',
                           reference: 'http://watir.com/staleness-changes',
                           ids: [:stale_present]
  end
  displayed
rescue UnknownObjectException, UnknownFrameException
  false
end

#reset!Object


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

def reset!
  @element = nil
end

#right_clickObject

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

Examples:

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

206
207
208
209
# File 'lib/watir/elements/element.rb', line 206

def right_click
  element_call(:wait_for_present) { driver.action.context_click(@element).perform }
  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)

360
361
362
# File 'lib/watir/elements/element.rb', line 360

def 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.


650
651
652
653
654
# File 'lib/watir/elements/element.rb', line 650

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:


337
338
339
# File 'lib/watir/elements/element.rb', line 337

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)

386
387
388
# File 'lib/watir/elements/element.rb', line 386

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:


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

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)

595
596
597
598
599
600
# File 'lib/watir/elements/element.rb', line 595

def stale_in_context?
  @element.css_value('staleness_check') # any wire call will check for staleness
  false
rescue Selenium::WebDriver::Error::ObsoleteElementError
  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)

533
534
535
536
537
538
539
# File 'lib/watir/elements/element.rb', line 533

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)

122
123
124
# File 'lib/watir/elements/element.rb', line 122

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

#textString

Returns the text of the element.

Returns:

  • (String)

112
113
114
# File 'lib/watir/elements/element.rb', line 112

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>

549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
# File 'lib/watir/elements/element.rb', line 549

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)

459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
# File 'lib/watir/elements/element.rb', line 459

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]
  displayed = display_check
  if displayed.nil? && display_check
    Watir.logger.deprecate 'Checking `#visible? == false` to determine a stale element',
                           '`#stale? == true`',
                           reference: 'http://watir.com/staleness-changes',
                           ids: [:stale_visible]
  end
  raise unknown_exception if displayed.nil?

  displayed
end

#wdSelenium::WebDriver::Element

Returns underlying Selenium object of the Watir Element

Returns:

  • (Selenium::WebDriver::Element)

447
448
449
450
# File 'lib/watir/elements/element.rb', line 447

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)

412
413
414
# File 'lib/watir/elements/element.rb', line 412

def width
  size['width']
end