Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
SeleniumHQ
GitHub Repository: SeleniumHQ/Selenium
Path: blob/trunk/rb/lib/selenium/webdriver/common/element.rb
1865 views
1
# frozen_string_literal: true
2
3
# Licensed to the Software Freedom Conservancy (SFC) under one
4
# or more contributor license agreements. See the NOTICE file
5
# distributed with this work for additional information
6
# regarding copyright ownership. The SFC licenses this file
7
# to you under the Apache License, Version 2.0 (the
8
# "License"); you may not use this file except in compliance
9
# with the License. You may obtain a copy of the License at
10
#
11
# http://www.apache.org/licenses/LICENSE-2.0
12
#
13
# Unless required by applicable law or agreed to in writing,
14
# software distributed under the License is distributed on an
15
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16
# KIND, either express or implied. See the License for the
17
# specific language governing permissions and limitations
18
# under the License.
19
20
module Selenium
21
module WebDriver
22
class Element
23
ELEMENT_KEY = 'element-6066-11e4-a52e-4f735466cecf'
24
25
include SearchContext
26
include TakesScreenshot
27
28
#
29
# Creates a new Element
30
#
31
# @api private
32
#
33
34
def initialize(bridge, id)
35
@bridge = bridge
36
@id = id
37
end
38
39
def inspect
40
format '#<%<class>s:0x%<hash>x id=%<id>s>', class: self.class, hash: hash * 2, id: @id.inspect
41
end
42
43
def ==(other)
44
other.is_a?(self.class) && ref == other.ref
45
end
46
alias eql? ==
47
48
def hash
49
[@id, @bridge].hash
50
end
51
52
#
53
# Click this element. If this causes a new page to load, this method will
54
# attempt to block until the page has loaded. At this point, you should
55
# discard all references to this element and any further operations
56
# performed on this element will raise a StaleElementReferenceError
57
# unless you know that the element and the page will still be present. If
58
# click() causes a new page to be loaded via an event or is done by
59
# sending a native event then the method will *not* wait for it to be
60
# loaded and the caller should verify that a new page has been loaded.
61
#
62
# There are some preconditions for an element to be clicked. The element
63
# must be visible and it must have a height and width greater then 0.
64
#
65
# Equivalent to:
66
# driver.action.click(element)
67
#
68
# @example Click on a button
69
#
70
# driver.find_element(tag_name: "button").click
71
#
72
# @raise [StaleElementReferenceError] if the element no longer exists as
73
# defined
74
#
75
76
def click
77
bridge.click_element @id
78
end
79
80
#
81
# Get the tag name of the element.
82
#
83
# @example Get the tagname of an INPUT element(returns "input")
84
#
85
# driver.find_element(xpath: "//input").tag_name
86
#
87
# @return [String] The tag name of this element.
88
#
89
90
def tag_name
91
bridge.element_tag_name @id
92
end
93
94
#
95
# This method attempts to provide the most likely desired current value for the attribute
96
# of the element, even when that desired value is actually a JavaScript property.
97
# It is implemented with a custom JavaScript atom. To obtain the exact value of the attribute or property,
98
# use #dom_attribute or #property methods respectively.
99
#
100
# More exactly, this method will return the value of the property with the given name,
101
# if it exists. If it does not, then the value of the attribute with the given name is returned.
102
# If neither exists, null is returned.
103
#
104
# The "style" attribute is converted as best can be to a text representation with a trailing semicolon.
105
#
106
# The following are deemed to be "boolean" attributes, and will return either "true" or "false":
107
#
108
# async, autofocus, autoplay, checked, compact, complete, controls, declare, defaultchecked,
109
# defaultselected, defer, disabled, draggable, ended, formnovalidate, hidden, indeterminate,
110
# iscontenteditable, ismap, itemscope, loop, multiple, muted, nohref, noresize, noshade, novalidate,
111
# nowrap, open, paused, pubdate, readonly, required, reversed, scoped, seamless, seeking,
112
# selected, spellcheck, truespeed, willvalidate
113
#
114
# Finally, the following commonly mis-capitalized attribute/property names are evaluated as expected:
115
#
116
# When the value of "class" is requested, the "className" property is returned.
117
# When the value of "readonly" is requested, the "readOnly" property is returned.
118
#
119
# @param [String] name attribute name
120
# @return [String, nil] attribute value
121
#
122
# @see #dom_attribute
123
# @see #property
124
#
125
126
def attribute(name)
127
bridge.element_attribute self, name
128
end
129
130
#
131
# Gets the value of a declared HTML attribute of this element.
132
#
133
# As opposed to the #attribute method, this method
134
# only returns attributes declared in the element's HTML markup.
135
#
136
# If the attribute is not set, nil is returned.
137
#
138
# @param [String] name attribute name
139
# @return [String, nil] attribute value
140
#
141
# @see #attribute
142
# @see #property
143
#
144
145
def dom_attribute(name)
146
bridge.element_dom_attribute @id, name
147
end
148
149
#
150
# Gets the value of a JavaScript property of this element
151
# This will return the current value,
152
# even if this has been modified after the page has been loaded.
153
# If the value is not set, nil is returned.
154
#
155
# @param [String] name property name
156
# @return [String, nil] property value
157
#
158
159
def property(name)
160
bridge.element_property @id, name
161
end
162
163
#
164
# Gets the computed WAI-ARIA role of element
165
#
166
# @return [String]
167
#
168
169
def aria_role
170
bridge.element_aria_role @id
171
end
172
173
#
174
# Gets the computed WAI-ARIA label of element.
175
#
176
# @return [String]
177
#
178
179
def accessible_name
180
bridge.element_aria_label @id
181
end
182
183
#
184
# Get the text content of this element
185
#
186
# @return [String]
187
#
188
189
def text
190
bridge.element_text @id
191
end
192
193
#
194
# Send keystrokes to this element
195
#
196
# @param [String, Symbol, Array] args keystrokes to send
197
#
198
# Examples:
199
#
200
# element.send_keys "foo" #=> value: 'foo'
201
# element.send_keys "tet", :arrow_left, "s" #=> value: 'test'
202
# element.send_keys [:control, 'a'], :space #=> value: ' '
203
#
204
# @see Keys::KEYS
205
#
206
207
def send_keys(*args)
208
bridge.send_keys_to_element @id, Keys.encode(args)
209
end
210
alias send_key send_keys
211
212
#
213
# If this element is a text entry element, this will clear the value. Has no effect on other
214
# elements. Text entry elements are INPUT and TEXTAREA elements.
215
#
216
# Note that the events fired by this event may not be as you'd expect. In particular, we don't
217
# fire any keyboard or mouse events. If you want to ensure keyboard events are
218
# fired, consider using #send_keys with the backspace key. To ensure you get a change event,
219
# consider following with a call to #send_keys with the tab key.
220
#
221
222
def clear
223
bridge.clear_element @id
224
end
225
226
#
227
# Is the element enabled?
228
#
229
# @return [Boolean]
230
#
231
232
def enabled?
233
bridge.element_enabled? @id
234
end
235
236
#
237
# Is the element selected?
238
#
239
# @return [Boolean]
240
#
241
242
def selected?
243
bridge.element_selected? @id
244
end
245
246
#
247
# Is the element displayed?
248
#
249
# @return [Boolean]
250
#
251
252
def displayed?
253
bridge.element_displayed? self
254
end
255
256
#
257
# Submit this element
258
#
259
260
def submit
261
bridge.submit_element @id
262
end
263
264
#
265
# Get the value of the given CSS property
266
#
267
# Note that shorthand CSS properties (e.g. background, font, border, border-top, margin,
268
# margin-top, padding, padding-top, list-style, outline, pause, cue) are not returned,
269
# in accordance with the DOM CSS2 specification - you should directly access the longhand
270
# properties (e.g. background-color) to access the desired values.
271
#
272
# @see http://www.w3.org/TR/DOM-Level-2-Style/css.html#CSS-CSSStyleDeclaration
273
#
274
275
def css_value(prop)
276
bridge.element_value_of_css_property @id, prop
277
end
278
alias style css_value
279
280
#
281
# Get the location of this element.
282
#
283
# @return [WebDriver::Point]
284
#
285
286
def location
287
bridge.element_location @id
288
end
289
290
#
291
# Get the dimensions and coordinates of this element.
292
#
293
# @return [WebDriver::Rectangle]
294
#
295
296
def rect
297
bridge.element_rect @id
298
end
299
300
#
301
# Determine an element's location on the screen once it has been scrolled into view.
302
#
303
# @return [WebDriver::Point]
304
#
305
306
def location_once_scrolled_into_view
307
bridge.element_location_once_scrolled_into_view @id
308
end
309
310
#
311
# Get the size of this element
312
#
313
# @return [WebDriver::Dimension]
314
#
315
316
def size
317
bridge.element_size @id
318
end
319
320
#
321
# Returns the shadow root of an element.
322
#
323
# @return [WebDriver::ShadowRoot]
324
#
325
326
def shadow_root
327
bridge.shadow_root @id
328
end
329
330
#-------------------------------- sugar --------------------------------
331
332
#
333
# element.first(id: 'foo')
334
#
335
336
alias first find_element
337
338
#
339
# element.all(class: 'bar')
340
#
341
342
alias all find_elements
343
344
#
345
# element['class'] or element[:class] #=> "someclass"
346
#
347
alias [] attribute
348
349
#
350
# @api private
351
# @see SearchContext
352
#
353
354
def ref
355
[:element, @id]
356
end
357
358
#
359
# Convert to a WebElement JSON Object for transmission over the wire.
360
# @see https://github.com/SeleniumHQ/selenium/wiki/JsonWireProtocol#basic-terms-and-concepts
361
#
362
# @api private
363
#
364
365
def to_json(*)
366
JSON.generate as_json
367
end
368
369
#
370
# For Rails 3 - http://jonathanjulian.com/2010/04/rails-to_json-or-as_json/
371
#
372
# @api private
373
#
374
375
def as_json(*)
376
@id.is_a?(Hash) ? @id : {ELEMENT_KEY => @id}
377
end
378
379
private
380
381
attr_reader :bridge
382
383
def selectable?
384
tn = tag_name.downcase
385
type = attribute(:type).to_s.downcase
386
387
tn == 'option' || (tn == 'input' && %w[radio checkbox].include?(type))
388
end
389
390
def screenshot
391
bridge.element_screenshot(@id)
392
end
393
end # Element
394
end # WebDriver
395
end # Selenium
396
397