Skip to content

Commit c1106aa

Browse files
authored
fix returning only visible elements (#465)
* fix tags to return only visible elements * fix rubocop * set visible check * remove some wrong cases * fix single quote's escape
1 parent 0104a87 commit c1106aa

File tree

11 files changed

+76
-58
lines changed

11 files changed

+76
-58
lines changed

ios_tests/appium.txt

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[caps]
22
platformName = "ios"
3-
platformVersion = "10.1"
3+
platformVersion = "10.2"
44
deviceName ="iPhone Simulator"
55
automationName = 'XCUITest'
66
app = "./UICatalog.app"

ios_tests/lib/ios/specs/common/helper.rb

+1-1
Original file line numberDiff line numberDiff line change
@@ -146,7 +146,7 @@ def uibutton_text
146146
end
147147

148148
t 'last_ele' do
149-
expected = UI::Inventory.xcuitest? ? 'Shows UIViewAnimationTransitions' : 'Transitions'
149+
expected = 'Transitions'
150150

151151
el = last_ele(UI::Inventory.static_text)
152152
el.text.must_equal expected

ios_tests/lib/ios/specs/ios/element/button.rb

+1-2
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,6 @@ def gray
2929

3030
t 'buttons' do
3131
exp = ['Back', 'Back', 'Gray', 'Right pointing arrow']
32-
exp.concat ['Add contact'] if UI::Inventory.xcuitest?
3332

3433
target_buttons = buttons('a')
3534
target_buttons.map(&:name).must_equal exp
@@ -41,7 +40,7 @@ def gray
4140
end
4241

4342
t 'last_button' do
44-
expected = UI::Inventory.xcuitest? ? 'Add contact' : 'Rounded'
43+
expected = 'Rounded'
4544
last_button.name.must_equal expected
4645
end
4746

ios_tests/lib/ios/specs/ios/element/text.rb

+2-2
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ def before_first
2323
end
2424

2525
t 'last_text' do
26-
expected = UI::Inventory.xcuitest? ? 'Shows UIViewAnimationTransitions' : 'Transitions'
26+
expected = 'Transitions'
2727

2828
last_text.text.must_equal expected
2929
last_text.name.must_equal expected
@@ -37,7 +37,7 @@ def before_first
3737

3838
t 'texts' do
3939
exp = ['Controls', 'Various uses of UIControl', 'Various uses of UISegmentedControl']
40-
texts.length.must_equal(UI::Inventory.xcuitest? ? 25 : 24)
40+
texts.length.must_equal 24
4141
texts('trol').map(&:name).must_equal exp
4242
texts('uses').length.must_equal 7
4343
end

ios_tests/lib/ios/specs/ios/element/textfield.rb

+3-1
Original file line numberDiff line numberDiff line change
@@ -71,9 +71,11 @@ def keyboard_must_exist
7171
t 'textfield type' do
7272
# Regular send keys triggers the keyboard and doesn't dismiss
7373
keyboard_must_not_exist unless UI::Inventory.xcuitest? # xcuitest doesn't support JS command
74-
textfield(1).send_keys 'ok'
74+
textfield(1).send_keys "o'k"
7575
keyboard_must_exist unless UI::Inventory.xcuitest? # xcuitest doesn't support JS command
7676

77+
find_exact("o'k").text.must_equal "o'k"
78+
7779
unless UI::Inventory.xcuitest?
7880
# type should not dismiss the keyboard
7981
message = 'type test type'

ios_tests/lib/ios/specs/ios/patch.rb

+1-6
Original file line numberDiff line numberDiff line change
@@ -14,12 +14,7 @@ def after_last
1414
end
1515

1616
t 'label' do
17-
if UI::Inventory.xcuitest?
18-
# Order of the elements are: Normal, Rounded, Secure, Check
19-
find_element(:name, '<enter text>').label.must_equal 'Normal'
20-
else
21-
textfield('<enter text>').label.must_equal 'Rounded'
22-
end
17+
textfield('<enter text>').label.must_equal 'Rounded'
2318
end
2419

2520
t 'type' do

lib/appium_lib/ios/element/button.rb

+6-6
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ def button(value)
1818
return ele_index button_class, value if value.is_a? Numeric
1919

2020
if automation_name_is_xcuitest?
21-
_raise_error_if_no_element buttons(value).first
21+
raise_error_if_no_element buttons(value).first
2222
else
2323
ele_by_json_visible_contains button_class, value
2424
end
@@ -32,8 +32,8 @@ def buttons(value = false)
3232
return tags button_class unless value
3333

3434
if automation_name_is_xcuitest?
35-
elements = tags button_class
36-
_elements_include elements, value
35+
visible_elements = tags button_class
36+
elements_include visible_elements, value
3737
else
3838
eles_by_json_visible_contains button_class, value
3939
end
@@ -58,7 +58,7 @@ def last_button
5858
# @return [UIAButton|XCUIElementTypeButton]
5959
def button_exact(value)
6060
if automation_name_is_xcuitest?
61-
_raise_error_if_no_element buttons_exact(value).first
61+
raise_error_if_no_element buttons_exact(value).first
6262
else
6363
ele_by_json_visible_exact button_class, value
6464
end
@@ -69,8 +69,8 @@ def button_exact(value)
6969
# @return [Array<UIAButton|XCUIElementTypeButton>]
7070
def buttons_exact(value)
7171
if automation_name_is_xcuitest?
72-
elements = tags button_class
73-
_elements_exact elements, value
72+
visible_elements = tags button_class
73+
elements_exact visible_elements, value
7474
else
7575
eles_by_json_visible_exact button_class, value
7676
end

lib/appium_lib/ios/element/generic.rb

+30-10
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ module Ios
55
# @return [Element]
66
def find(value)
77
if automation_name_is_xcuitest?
8-
find_ele_by_attr_include '*', '*', value
8+
raise_error_if_no_element finds(value).first
99
else
1010
ele_by_json_visible_contains '*', value
1111
end
@@ -16,7 +16,8 @@ def find(value)
1616
# @return [Array<Element>]
1717
def finds(value)
1818
if automation_name_is_xcuitest?
19-
find_eles_by_attr_include '*', '*', value
19+
elements = find_eles_by_attr_include '*', '*', value
20+
select_visible_elements elements
2021
else
2122
eles_by_json_visible_contains '*', value
2223
end
@@ -27,7 +28,7 @@ def finds(value)
2728
# @return [Element]
2829
def find_exact(value)
2930
if automation_name_is_xcuitest?
30-
find_ele_by_attr '*', '*', value
31+
raise_error_if_no_element finds_exact(value).first
3132
else
3233
ele_by_json_visible_exact '*', value
3334
end
@@ -38,33 +39,52 @@ def find_exact(value)
3839
# @return [Array<Element>]
3940
def finds_exact(value)
4041
if automation_name_is_xcuitest?
41-
find_eles_by_attr '*', '*', value
42+
elements = find_eles_by_attr '*', '*', value
43+
select_visible_elements elements
4244
else
4345
eles_by_json_visible_exact '*', value
4446
end
4547
end
4648

4749
private
4850

49-
def _raise_error_if_no_element(element)
50-
raise ::Selenium::WebDriver::Error::NoSuchElementError if element.nil?
51+
def raise_error_if_no_element(element)
52+
error_message = 'An element could not be located on the page using the given search parameters.'
53+
raise(::Selenium::WebDriver::Error::NoSuchElementError, error_message) if element.nil?
5154
element
5255
end
5356

54-
def _elements_include(elements, value)
57+
# Return all elements include not displayed elements.
58+
def elements_include(elements, value)
5559
return [] if elements.empty?
5660
elements.select do |element|
61+
# `text` is equal to `value` if value is not `nil`
62+
# `text` is equal to `name` if value is `nil`
5763
name = element.name
58-
name.nil? ? false : name.downcase.include?(value.downcase)
64+
text = element.value
65+
name_result = name.nil? ? false : name.downcase.include?(value.downcase)
66+
text_result = text.nil? ? false : text.downcase.include?(value.downcase)
67+
name_result || text_result
5968
end
6069
end
6170

62-
def _elements_exact(elements, value)
71+
# Return all elements include not displayed elements.
72+
def elements_exact(elements, value)
6373
return [] if elements.empty?
6474
elements.select do |element|
75+
# `text` is equal to `value` if value is not `nil`
76+
# `text` is equal to `name` if value is `nil`
6577
name = element.name
66-
name.nil? ? false : name.casecmp(value).zero?
78+
text = element.value
79+
name_result = name.nil? ? false : name.casecmp(value).zero?
80+
text_result = text.nil? ? false : text.casecmp(value).zero?
81+
name_result || text_result
6782
end
6883
end
84+
85+
# Return visible elements.
86+
def select_visible_elements(elements)
87+
elements.select(&:displayed?)
88+
end
6989
end # module Ios
7090
end # module Appium

lib/appium_lib/ios/element/text.rb

+6-6
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ def text(value)
1717
return ele_index static_text_class, value if value.is_a? Numeric
1818

1919
if automation_name_is_xcuitest?
20-
_raise_error_if_no_element texts(value).first
20+
raise_error_if_no_element texts(value).first
2121
else
2222
ele_by_json_visible_contains static_text_class, value
2323
end
@@ -31,8 +31,8 @@ def texts(value = false)
3131
return tags static_text_class unless value
3232

3333
if automation_name_is_xcuitest?
34-
elements = tags static_text_class
35-
_elements_include elements, value
34+
visible_elements = tags static_text_class
35+
elements_include visible_elements, value
3636
else
3737
eles_by_json_visible_contains static_text_class, value
3838
end
@@ -55,7 +55,7 @@ def last_text
5555
# @return [UIAStaticText|XCUIElementTypeStaticText]
5656
def text_exact(value)
5757
if automation_name_is_xcuitest?
58-
_raise_error_if_no_element texts_exact(value).first
58+
raise_error_if_no_element texts_exact(value).first
5959
else
6060
ele_by_json_visible_exact static_text_class, value
6161
end
@@ -66,8 +66,8 @@ def text_exact(value)
6666
# @return [Array<UIAStaticText|XCUIElementTypeStaticText>]
6767
def texts_exact(value)
6868
if automation_name_is_xcuitest?
69-
elements = tags static_text_class
70-
_elements_exact elements, value
69+
visible_elements = tags static_text_class
70+
elements_exact visible_elements, value
7171
else
7272
eles_by_json_visible_exact static_text_class, value
7373
end

lib/appium_lib/ios/element/textfield.rb

+9-6
Original file line numberDiff line numberDiff line change
@@ -27,13 +27,14 @@ def _textfields
2727
# @private
2828
# for XCUITest
2929
def _textfield_with_xpath
30-
xpath "//#{_textfields}"
30+
raise_error_if_no_element _textfields_with_xpath.first
3131
end
3232

3333
# @private
3434
# for XCUITest
3535
def _textfields_with_xpath
36-
xpaths "//#{_textfields}"
36+
elements = xpaths "//#{_textfields}"
37+
select_visible_elements elements
3738
end
3839

3940
# Appium
@@ -78,7 +79,7 @@ def textfield(value)
7879
end
7980

8081
if automation_name_is_xcuitest?
81-
find_ele_by_attr_include _textfields, '*', value
82+
raise_error_if_no_element textfields(value).first
8283
else
8384
ele_by_json _textfield_contains_string value
8485
end
@@ -91,7 +92,8 @@ def textfield(value)
9192
def textfields(value = false)
9293
if automation_name_is_xcuitest?
9394
return _textfields_with_xpath unless value
94-
find_eles_by_attr_include _textfields, '*', value
95+
elements = find_eles_by_attr_include _textfields, '*', value
96+
select_visible_elements elements
9597
else
9698
return eles_by_json _textfield_visible unless value
9799
eles_by_json _textfield_contains_string value
@@ -125,7 +127,7 @@ def last_textfield
125127
# @return [TextField]
126128
def textfield_exact(value)
127129
if automation_name_is_xcuitest?
128-
find_ele_by_attr _textfields, '*', value
130+
raise_error_if_no_element textfields_exact(value).first
129131
else
130132
ele_by_json _textfield_exact_string value
131133
end
@@ -136,7 +138,8 @@ def textfield_exact(value)
136138
# @return [Array<TextField>]
137139
def textfields_exact(value)
138140
if automation_name_is_xcuitest?
139-
find_eles_by_attr _textfields, '*', value
141+
elements = find_eles_by_attr _textfields, '*', value
142+
select_visible_elements elements
140143
else
141144
eles_by_json _textfield_exact_string value
142145
end

lib/appium_lib/ios/helper.rb

+16-17
Original file line numberDiff line numberDiff line change
@@ -229,17 +229,18 @@ def ele_index(class_name, index)
229229
def string_attr_exact(class_name, attr, value)
230230
if automation_name_is_xcuitest?
231231
if attr == '*'
232-
%((//#{class_name})[@*[.='#{value}']])
232+
%((//#{class_name})[@*[.="#{value}"]])
233233
else
234-
%((//#{class_name})[@#{attr}='#{value}'])
234+
%((//#{class_name})[@#{attr}="#{value}"])
235235
end
236236
else
237-
%(//#{class_name}[@visible="true" and @#{attr}='#{value}'])
237+
%(//#{class_name}[@visible="true" and @#{attr}="#{value}"])
238238
end
239239
end
240240

241241
# Find the first element exactly matching class and attribute value.
242242
# Note: Uses XPath
243+
# Note: For XCUITest, this method return ALL elements include displayed or not displayed elements.
243244
# @param class_name [String] the class name to search for
244245
# @param attr [String] the attribute to inspect
245246
# @param value [String] the expected value of the attribute
@@ -250,6 +251,7 @@ def find_ele_by_attr(class_name, attr, value)
250251

251252
# Find all elements exactly matching class and attribute value.
252253
# Note: Uses XPath
254+
# Note: For XCUITest, this method return ALL elements include displayed or not displayed elements.
253255
# @param class_name [String] the class name to match
254256
# @param attr [String] the attribute to compare
255257
# @param value [String] the value of the attribute that the element must have
@@ -262,12 +264,12 @@ def find_eles_by_attr(class_name, attr, value)
262264
def string_attr_include(class_name, attr, value)
263265
if automation_name_is_xcuitest?
264266
if attr == '*'
265-
%((//#{class_name})[@*[contains(translate(., '#{value.upcase}', '#{value}'), '#{value}')]])
267+
%((//#{class_name})[@*[contains(translate(., "#{value.upcase}", "#{value}"), "#{value}")]])
266268
else
267-
%((//#{class_name})[contains(translate(@#{attr}, '#{value.upcase}', '#{value}'), '#{value}')])
269+
%((//#{class_name})[contains(translate(@#{attr}, "#{value.upcase}", "#{value}"), "#{value}")])
268270
end
269271
else
270-
%(//#{class_name}[@visible="true" and contains(translate(@#{attr},'#{value.upcase}', '#{value}'), '#{value}')])
272+
%(//#{class_name}[@visible="true" and contains(translate(@#{attr},"#{value.upcase}", "#{value}"), "#{value}")])
271273
end
272274
end
273275

@@ -295,33 +297,29 @@ def find_eles_by_attr_include(class_name, attr, value)
295297
# @param class_name [String] the tag to match
296298
# @return [Element]
297299
def first_ele(class_name)
298-
if automation_name_is_xcuitest?
299-
@driver.find_element :class, class_name
300-
else
301-
ele_index class_name, 1
302-
end
300+
ele_index class_name, 1
303301
end
304302

305303
# Get the last tag that matches class_name
306304
# @param class_name [String] the tag to match
307305
# @return [Element]
308306
def last_ele(class_name)
309307
if automation_name_is_xcuitest?
310-
result = @driver.find_elements :xpath, "(//#{class_name})"
311-
raise _no_such_element if result.empty?
312-
result.last
308+
visible_elements = tags class_name
309+
raise _no_such_element if visible_elements.empty?
310+
visible_elements.last
313311
else
314312
ele_index class_name, 'last()'
315313
end
316314
end
317315

318-
# Returns the first visible element matching class_name
316+
# Returns the first **visible** element matching class_name
319317
#
320318
# @param class_name [String] the class_name to search for
321319
# @return [Element]
322320
def tag(class_name)
323321
if automation_name_is_xcuitest?
324-
first_ele(class_name)
322+
raise_error_if_no_element tags(class_name).first
325323
else
326324
ele_by_json(typeArray: [class_name], onlyVisible: true)
327325
end
@@ -333,7 +331,8 @@ def tag(class_name)
333331
# @return [Element]
334332
def tags(class_name)
335333
if automation_name_is_xcuitest?
336-
@driver.find_elements :class, class_name
334+
elements = @driver.find_elements :class, class_name
335+
select_visible_elements elements
337336
else
338337
eles_by_json(typeArray: [class_name], onlyVisible: true)
339338
end

0 commit comments

Comments
 (0)