appium_lib 0.3.16 → 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +8 -8
- data/Rakefile +17 -1
- data/docs/android_docs.md +1328 -0
- data/{docs.md → docs/docs.md} +2 -1
- data/docs/ios_docs.md +1362 -0
- data/docs_gen/docs_from_js.md +44 -0
- data/docs_gen/make_docs.rb +81 -0
- data/lib/appium_lib.rb +3 -1
- data/lib/appium_lib/android/element/alert.rb +1 -1
- data/lib/appium_lib/android/element/generic.rb +19 -13
- data/lib/appium_lib/android/helper.rb +21 -3
- data/lib/appium_lib/android/patch.rb +1 -0
- data/lib/appium_lib/common/dynamic.rb +44 -0
- data/lib/appium_lib/common/helper.rb +21 -11
- data/lib/appium_lib/common/patch.rb +45 -6
- data/lib/appium_lib/common/version.rb +2 -2
- data/lib/appium_lib/driver.rb +59 -12
- data/lib/appium_lib/ios/element/generic.rb +6 -7
- data/lib/appium_lib/ios/element/textfield.rb +1 -0
- data/lib/appium_lib/ios/helper.rb +14 -4
- data/lib/appium_lib/ios/patch.rb +1 -13
- data/readme.md +3 -1
- data/release_notes.md +35 -151
- metadata +9 -3
@@ -0,0 +1,44 @@
|
|
1
|
+
Automatically convert yard's HTML output to Markdown. Run in Chrome Dev Tools console.
|
2
|
+
|
3
|
+
```javascript
|
4
|
+
// http://localhost:8808/docs/toplevel
|
5
|
+
|
6
|
+
var methods = $x('//*[@id="content"]/ul/li');
|
7
|
+
|
8
|
+
var sig = function(method) { return method.children[0].children[0].textContent.trim().substr(2); };
|
9
|
+
var desc = function(method) { return method.children[1].children[0].textContent.trim(); };
|
10
|
+
|
11
|
+
// All element methods must include the element name.
|
12
|
+
// Check textfield before text because text is included in textfield.
|
13
|
+
var elements = [ 'alert', 'button', 'textfield', 'text', 'window' ];
|
14
|
+
var output = {};
|
15
|
+
|
16
|
+
for (var b = 0; b < elements.length; b++) {
|
17
|
+
output[elements[b]] = [];
|
18
|
+
}
|
19
|
+
|
20
|
+
for (var a = 0; a < methods.length; a++) {
|
21
|
+
var name = sig(methods[a]);
|
22
|
+
var text = desc(methods[a]);
|
23
|
+
var index = '';
|
24
|
+
|
25
|
+
for (var b = 0; b < elements.length; b++) {
|
26
|
+
if (name.indexOf(elements[b]) !== -1 && name.indexOf('find_ele') === -1) {
|
27
|
+
index = elements[b];
|
28
|
+
break;
|
29
|
+
}
|
30
|
+
}
|
31
|
+
|
32
|
+
if (index === '') { continue; }
|
33
|
+
output[index].push( [name, text] );
|
34
|
+
}
|
35
|
+
|
36
|
+
for (var b = 0; b < elements.length; b++) {
|
37
|
+
var eles = output[elements[b]];
|
38
|
+
console.log("\n" + '#### ' + elements[b]);
|
39
|
+
for (var c = 0; c < eles.length; c++) {
|
40
|
+
var ele = eles[c];
|
41
|
+
console.log('0. `' + ele[0] + '` ' + ele[1]);
|
42
|
+
}
|
43
|
+
}
|
44
|
+
```
|
@@ -0,0 +1,81 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
require 'rubygems'
|
4
|
+
require 'yard'
|
5
|
+
|
6
|
+
def space amount
|
7
|
+
' ' * amount
|
8
|
+
end
|
9
|
+
|
10
|
+
def last_sha
|
11
|
+
`git rev-parse --verify HEAD`.strip
|
12
|
+
end
|
13
|
+
|
14
|
+
def mobj_to_md obj
|
15
|
+
out = ''
|
16
|
+
# skip objects without method signatures
|
17
|
+
sig = obj.signature
|
18
|
+
return out unless sig
|
19
|
+
|
20
|
+
# skip class vars
|
21
|
+
if sig.start_with?('@@') ||
|
22
|
+
# skip methods marked private
|
23
|
+
obj.tag('private') ||
|
24
|
+
# skip date and version from version.rb
|
25
|
+
obj.name.match(/DATE|VERSION/)
|
26
|
+
return out
|
27
|
+
end
|
28
|
+
|
29
|
+
method_path = obj.file.split('/lib/').last
|
30
|
+
os = method_path.downcase.match /ios|android/
|
31
|
+
out += "##### [#{obj.name.to_s}](https://github.com/appium/ruby_lib/blob/#{last_sha}/lib/#{method_path}#L#{obj.line}) #{os}\n\n"
|
32
|
+
out += "> #{obj.signature}\n\n"
|
33
|
+
out += "#{obj.docstring}\n\n"
|
34
|
+
|
35
|
+
|
36
|
+
indent = space 5
|
37
|
+
params = obj.tags.select { |tag| tag.tag_name == 'param' }
|
38
|
+
if !params.empty?
|
39
|
+
out += "__Parameters:__\n\n"
|
40
|
+
params.each do |param|
|
41
|
+
out += indent + "[#{param.types.join ', '}] "
|
42
|
+
out += "#{param.name} - #{param.text}\n\n"
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
ret = obj.tag 'return'
|
47
|
+
if ret
|
48
|
+
out += "__Returns:__\n\n"
|
49
|
+
out += indent + "[#{ret.types.join ', '}] #{ret.text}\n\n"
|
50
|
+
end
|
51
|
+
out += "--\n\n"
|
52
|
+
|
53
|
+
out
|
54
|
+
end
|
55
|
+
|
56
|
+
def run out_file, globs
|
57
|
+
YARD::Registry.clear
|
58
|
+
puts "Globbing: #{globs}"
|
59
|
+
puts "Writing: #{out_file}"
|
60
|
+
YARD::Parser::SourceParser.parse globs
|
61
|
+
File.open(out_file, 'w') do | file |
|
62
|
+
YARD::Registry.entries.each do | entry |
|
63
|
+
file.write mobj_to_md entry
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
def globs paths
|
69
|
+
# Convert single string to array for map
|
70
|
+
paths = [ paths ] unless paths.kind_of? Array
|
71
|
+
# Adjust path based on system
|
72
|
+
paths.map! { |path| "#{ENV['HOME']}/Desktop/appium/ruby_lib#{path}" }
|
73
|
+
end
|
74
|
+
|
75
|
+
common_globs = '/lib/appium_lib/*.rb', '/lib/appium_lib/common/**/*.rb'
|
76
|
+
android_globs = common_globs + [ '/lib/appium_lib/android/**/*.rb' ]
|
77
|
+
ios_globs = common_globs + [ '/lib/appium_lib/ios/**/*.rb' ]
|
78
|
+
|
79
|
+
run 'docs/android_docs.md', globs(android_globs)
|
80
|
+
|
81
|
+
run 'docs/ios_docs.md', globs(ios_globs)
|
data/lib/appium_lib.rb
CHANGED
@@ -2,6 +2,7 @@
|
|
2
2
|
|
3
3
|
$driver = nil
|
4
4
|
|
5
|
+
# @private
|
5
6
|
# Invoke top level methods on last created Appium driver.
|
6
7
|
def self.method_missing method, *args, &block
|
7
8
|
raise "driver is nil. called #{method}" if $driver == nil
|
@@ -12,6 +13,7 @@ def self.method_missing method, *args, &block
|
|
12
13
|
end
|
13
14
|
|
14
15
|
module Appium
|
16
|
+
# @private
|
15
17
|
def self.add_to_path file, path=false
|
16
18
|
path = path ? "../#{path}/" : '..'
|
17
19
|
path = File.expand_path path, file
|
@@ -22,4 +24,4 @@ module Appium
|
|
22
24
|
add_to_path __FILE__
|
23
25
|
|
24
26
|
require 'appium_lib/driver'
|
25
|
-
end
|
27
|
+
end
|
@@ -8,22 +8,22 @@ In Android //* is used to find partial case insensitive text matches.
|
|
8
8
|
|
9
9
|
find_element :name by default uses a partial case insensitive match.
|
10
10
|
On iOS the default is an exact name match.
|
11
|
-
=end
|
12
11
|
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
12
|
+
```javascript
|
13
|
+
// iOS version
|
14
|
+
// https://github.com/appium/ruby_lib/blob/37bb4e90b29e5adb4438b287b6387a504c94b5c4/lib/appium_lib/element/ios/generic.rb#L23
|
15
|
+
var search = "name contains[c] '#{text}' || label contains[c] '#{text}' || value contains[c] '#{text}'";
|
16
|
+
var a = w.secureTextFields().firstWithPredicate(search);
|
17
|
+
if ( isNil(a) ) {
|
18
|
+
a = w.textFields().firstWithPredicate(search);
|
19
|
+
if ( isNil(a) ) {
|
20
|
+
a = w.buttons().firstWithPredicate(search);
|
18
21
|
if ( isNil(a) ) {
|
19
|
-
a = w.
|
20
|
-
if ( isNil(a) ) {
|
21
|
-
a = w.buttons().firstWithPredicate(search);
|
22
|
-
if ( isNil(a) ) {
|
23
|
-
a = w.elements().firstWithPredicate(search);
|
24
|
-
}
|
25
|
-
}
|
22
|
+
a = w.elements().firstWithPredicate(search);
|
26
23
|
}
|
24
|
+
}
|
25
|
+
}
|
26
|
+
```
|
27
27
|
|
28
28
|
Android considers both a textfield and a secure textfield to be "EditText".
|
29
29
|
Name (the content desc) is searched first and then we search for value (text).
|
@@ -35,6 +35,12 @@ so we consider the element a button if the class name contains the word button.
|
|
35
35
|
After looking for textfields and buttons, then we search all elements. Find will return
|
36
36
|
the first element that matches.
|
37
37
|
=end
|
38
|
+
|
39
|
+
# Find the value contained in content description or text. Search elements
|
40
|
+
# in this order: EditText, Button, ImageButton
|
41
|
+
#
|
42
|
+
# @param val [String] the value to search for
|
43
|
+
# @return [Element]
|
38
44
|
def find val
|
39
45
|
# s.className('android.widget.EditText').descriptionContains(value);
|
40
46
|
args = [ [4, 'android.widget.EditText'], [7, val] ],
|
@@ -1,9 +1,12 @@
|
|
1
1
|
# encoding: utf-8
|
2
2
|
module Appium::Android
|
3
3
|
# Returns an array of android classes that match the tag name
|
4
|
+
# @param tag_name [String] the tag name to convert to an android class
|
5
|
+
# @return [String]
|
4
6
|
def tag_name_to_android tag_name
|
5
7
|
tag_name = tag_name.to_s.downcase.strip
|
6
8
|
|
9
|
+
# @private
|
7
10
|
def prefix *tags
|
8
11
|
tags.map!{ |tag| "android.widget.#{tag}" }
|
9
12
|
end
|
@@ -33,8 +36,11 @@ module Appium::Android
|
|
33
36
|
raise "Invalid tag name #{tag_name}"
|
34
37
|
end # return result of case
|
35
38
|
end
|
36
|
-
|
37
|
-
#
|
39
|
+
# Find all elements matching the attribute
|
40
|
+
# On android, assume the attr is name (which falls back to text).
|
41
|
+
#
|
42
|
+
# @param tag_name [String] the tag name to search for
|
43
|
+
# @return [Element]
|
38
44
|
def find_eles_attr tag_name
|
39
45
|
=begin
|
40
46
|
sel1 = [ [4, 'android.widget.Button'], [100] ]
|
@@ -54,7 +60,11 @@ module Appium::Android
|
|
54
60
|
mobile :find, array
|
55
61
|
end
|
56
62
|
|
63
|
+
# Selendroid only.
|
64
|
+
# Returns a string containing interesting elements.
|
65
|
+
# @return [String]
|
57
66
|
def get_selendroid_inspect
|
67
|
+
# @private
|
58
68
|
def run node
|
59
69
|
r = []
|
60
70
|
|
@@ -116,7 +126,10 @@ module Appium::Android
|
|
116
126
|
end
|
117
127
|
|
118
128
|
# Android only.
|
129
|
+
# Returns a string containing interesting elements.
|
130
|
+
# @return [String]
|
119
131
|
def get_android_inspect
|
132
|
+
# @private
|
120
133
|
def run node
|
121
134
|
r = []
|
122
135
|
|
@@ -161,11 +174,14 @@ module Appium::Android
|
|
161
174
|
out
|
162
175
|
end
|
163
176
|
|
177
|
+
# Automatically detects selendroid or android.
|
178
|
+
# Returns a string containing interesting elements.
|
179
|
+
# @return [String]
|
164
180
|
def get_inspect
|
165
181
|
@selendroid ? get_selendroid_inspect : get_android_inspect
|
166
182
|
end
|
167
183
|
|
168
|
-
#
|
184
|
+
# Intended for use with console.
|
169
185
|
# Inspects and prints the current page.
|
170
186
|
def page
|
171
187
|
puts get_inspect
|
@@ -174,8 +190,10 @@ module Appium::Android
|
|
174
190
|
|
175
191
|
# JavaScript code from https://github.com/appium/appium/blob/master/app/android.js
|
176
192
|
#
|
193
|
+
# ```javascript
|
177
194
|
# Math.round((duration * 1000) / 200)
|
178
195
|
# (.20 * 1000) / 200 = 1
|
196
|
+
# ```
|
179
197
|
#
|
180
198
|
# We want steps to be exactly 1. If it's zero then a tap is used instead of a swipe.
|
181
199
|
def fast_duration
|
@@ -0,0 +1,44 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
module Appium
|
4
|
+
class Driver
|
5
|
+
@@map = {
|
6
|
+
1 => [ 'text(String text)', 'SELECTOR_TEXT', 1],
|
7
|
+
2 => [ 'textStartsWith(String text)', 'SELECTOR_START_TEXT', 2],
|
8
|
+
3 => [ 'textContains(String text)', 'SELECTOR_CONTAINS_TEXT', 3],
|
9
|
+
4 => [ 'className(String className)', 'SELECTOR_CLASS', 4],
|
10
|
+
5 => [ 'description(String desc)', 'SELECTOR_DESCRIPTION', 5],
|
11
|
+
6 => [ 'descriptionStartsWith(String desc)', 'SELECTOR_START_DESCRIPTION', 6],
|
12
|
+
7 => [ 'descriptionContains(String desc)', 'SELECTOR_CONTAINS_DESCRIPTION', 7],
|
13
|
+
8 => [ 'index(final int index)', 'SELECTOR_INDEX', 8],
|
14
|
+
9 => [ 'instance(final int instance)', 'SELECTOR_INSTANCE', 9],
|
15
|
+
10 => [ 'enabled(boolean val)', 'SELECTOR_ENABLED', 10],
|
16
|
+
11 => [ 'focused(boolean val)', 'SELECTOR_FOCUSED', 11],
|
17
|
+
12 => [ 'focusable(boolean val)', 'SELECTOR_FOCUSABLE', 12],
|
18
|
+
13 => [ 'scrollable(boolean val)', 'SELECTOR_SCROLLABLE', 13],
|
19
|
+
14 => [ 'clickable(boolean val)', 'SELECTOR_CLICKABLE', 14],
|
20
|
+
15 => [ 'checked(boolean val)', 'SELECTOR_CHECKED', 15],
|
21
|
+
16 => [ 'selected(boolean val)', 'SELECTOR_SELECTED', 16],
|
22
|
+
# // SELECTOR_ID = 17; // nothing.
|
23
|
+
18 => [ 'packageName(String name)', 'SELECTOR_PACKAGE_NAME', 18],
|
24
|
+
# // SELECTOR_CHILD = 19; // childSelector(UiSelector selector)
|
25
|
+
# // SELECTOR_CONTAINER = 20; // containerSelector(UiSelector selector)
|
26
|
+
# // SELECTOR_PATTERN = 21; // ! private ! patternSelector(UiSelector selector)
|
27
|
+
# // SELECTOR_PARENT = 22; // fromParent(UiSelector selector)
|
28
|
+
# // SELECTOR_COUNT = 23; // nothing.
|
29
|
+
24 => [ 'longClickable(boolean val)', 'SELECTOR_LONG_CLICKABLE', 24],
|
30
|
+
25 => [ 'textMatches(String regex)', 'SELECTOR_TEXT_REGEX', 25],
|
31
|
+
26 => [ 'classNameMatches(String regex)', 'SELECTOR_CLASS_REGEX', 26],
|
32
|
+
27 => [ 'descriptionMatches(String regex)', 'SELECTOR_DESCRIPTION_REGEX', 27],
|
33
|
+
28 => [ 'packageNameMatches(String regex)', 'SELECTOR_PACKAGE_NAME_REGEX', 28],
|
34
|
+
# // start internal methods at 100
|
35
|
+
100 => [ 'getStringAttribute("name")', 'GET_NAME', 100]
|
36
|
+
}
|
37
|
+
|
38
|
+
def dynamic_code_to_string code, value=false
|
39
|
+
result = @@map[code].first
|
40
|
+
return result unless value
|
41
|
+
result.split('(').first + "( \"#{value}\" )"
|
42
|
+
end
|
43
|
+
end # class Driver
|
44
|
+
end # module Appium
|
@@ -58,33 +58,35 @@ module Appium::Common
|
|
58
58
|
end
|
59
59
|
|
60
60
|
# Find by id. Useful for selendroid
|
61
|
+
# @param id [String] the id to search for
|
62
|
+
# @return [Element]
|
61
63
|
def id id
|
62
64
|
find_element :id, id
|
63
65
|
end
|
64
66
|
|
65
|
-
#
|
67
|
+
# Navigate back.
|
66
68
|
# @return [void]
|
67
69
|
def back
|
68
70
|
@driver.navigate.back
|
69
71
|
end
|
70
72
|
|
71
|
-
# For Sauce Labs reporting
|
73
|
+
# For Sauce Labs reporting. Returns the current session id.
|
72
74
|
def session_id
|
73
75
|
@driver.session_id
|
74
76
|
end
|
75
77
|
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
def sauce_access_key
|
81
|
-
@sauce_access_key
|
82
|
-
end
|
83
|
-
|
78
|
+
# Returns the first element that matches the provided xpath.
|
79
|
+
#
|
80
|
+
# @param xpath_str [String] the XPath string
|
81
|
+
# @return [Element]
|
84
82
|
def xpath xpath_str
|
85
83
|
find_element :xpath, xpath_str
|
86
84
|
end
|
87
85
|
|
86
|
+
# Returns all elements that match the provided xpath.
|
87
|
+
#
|
88
|
+
# @param xpath_str [String] the XPath string
|
89
|
+
# @return [Array<Element>]
|
88
90
|
def xpaths xpath_str
|
89
91
|
find_elements :xpath, xpath_str
|
90
92
|
end
|
@@ -185,11 +187,19 @@ module Appium::Common
|
|
185
187
|
JSON.parse @driver.page_source, max_nesting: 9999
|
186
188
|
end
|
187
189
|
|
190
|
+
# Returns the first element that matches name
|
191
|
+
#
|
192
|
+
# @param name [String] the name to match
|
193
|
+
# @return [Element]
|
188
194
|
def find_name name
|
189
195
|
find_element :name, name
|
190
196
|
end
|
191
197
|
|
198
|
+
# Returns all elements that match name
|
199
|
+
#
|
200
|
+
# @param name [String] the name to match
|
201
|
+
# @return [Array<Element>]
|
192
202
|
def find_names name
|
193
203
|
find_elements :name, name
|
194
204
|
end
|
195
|
-
end # module Appium::Common
|
205
|
+
end # module Appium::Common
|
@@ -4,19 +4,21 @@ module Appium::Common
|
|
4
4
|
class Selenium::WebDriver::Element
|
5
5
|
# Note: For testing .text should be used over value, and name.
|
6
6
|
|
7
|
-
#
|
7
|
+
# Returns the value attribute
|
8
|
+
#
|
9
|
+
# Fixes NoMethodError: undefined method `value' for Selenium::WebDriver::Element
|
8
10
|
def value
|
9
11
|
self.attribute :value
|
10
12
|
end
|
11
13
|
|
12
|
-
#
|
14
|
+
# Returns the name attribute
|
15
|
+
#
|
16
|
+
# Fixes NoMethodError: undefined method `name' for Selenium::WebDriver::Element
|
13
17
|
def name
|
14
18
|
self.attribute :name
|
15
19
|
end
|
16
20
|
|
17
|
-
#
|
18
|
-
#
|
19
|
-
# Tag name appears to be the same as type.
|
21
|
+
# Returns the type attribute
|
20
22
|
#
|
21
23
|
# Fixes Selenium::WebDriver::Error::UnknownError: Not yet implemented
|
22
24
|
def tag_name
|
@@ -25,7 +27,9 @@ module Appium::Common
|
|
25
27
|
|
26
28
|
# For use with mobile tap.
|
27
29
|
#
|
30
|
+
# ```ruby
|
28
31
|
# execute_script 'mobile: tap', :x => 0.0, :y => 0.98
|
32
|
+
# ```
|
29
33
|
#
|
30
34
|
# https://github.com/appium/appium/wiki/Automating-mobile-gestures
|
31
35
|
# @return [OpenStruct] the relative x, y in a struct. ex: { x: 0.50, y: 0.20 }
|
@@ -49,6 +53,7 @@ require 'selenium/webdriver/remote/commands'
|
|
49
53
|
require 'selenium/webdriver/remote/http/common'
|
50
54
|
require 'selenium/webdriver/remote/http/default'
|
51
55
|
|
56
|
+
# @private
|
52
57
|
# Show http calls to the Selenium server.
|
53
58
|
#
|
54
59
|
# Invaluable for debugging.
|
@@ -81,7 +86,40 @@ def patch_webdriver_bridge
|
|
81
86
|
unless command_hash.nil? || command_hash.length == 0
|
82
87
|
print_command = command_hash.clone
|
83
88
|
print_command.delete :args if print_command[:args] == []
|
84
|
-
|
89
|
+
|
90
|
+
mobile_find = 'mobile: find'
|
91
|
+
if print_command[:script] == mobile_find
|
92
|
+
args = print_command[:args]
|
93
|
+
puts "#{mobile_find}"#" #{args}"
|
94
|
+
|
95
|
+
# [[[[3, "sign"]]]] => [[[3, "sign"]]]
|
96
|
+
#
|
97
|
+
# [[[[4, "android.widget.EditText"], [7, "z"]], [[4, "android.widget.EditText"], [3, "z"]]]]
|
98
|
+
# => [[[4, "android.widget.EditText"], [7, "z"]], [[4, "android.widget.EditText"], [3, "z"]]]
|
99
|
+
args = args[0]
|
100
|
+
option = args[0].to_s.downcase
|
101
|
+
has_option = ! option.match(/all|scroll/).nil?
|
102
|
+
puts option if has_option
|
103
|
+
|
104
|
+
start = has_option ? 1 : 0
|
105
|
+
|
106
|
+
start.upto(args.length-1) do |selector_index|
|
107
|
+
selectors = args[selector_index]
|
108
|
+
selectors_size = selectors.length
|
109
|
+
selectors.each_index do |pair_index|
|
110
|
+
pair = selectors[pair_index]
|
111
|
+
res = $driver.dynamic_code_to_string pair[0], pair[1]
|
112
|
+
|
113
|
+
if selectors_size == 1 || pair_index >= selectors_size - 1
|
114
|
+
puts res
|
115
|
+
elsif selectors_size > 1 && pair_index < selectors_size
|
116
|
+
print res + '.'
|
117
|
+
end
|
118
|
+
end
|
119
|
+
end # start.upto
|
120
|
+
else
|
121
|
+
ap print_command
|
122
|
+
end
|
85
123
|
end
|
86
124
|
# puts "verb: #{verb}, path #{path}, command_hash #{command_hash.to_json}"
|
87
125
|
http.call verb, path, command_hash
|
@@ -91,6 +129,7 @@ end # def
|
|
91
129
|
|
92
130
|
# Print Appium's origValue error messages.
|
93
131
|
class Selenium::WebDriver::Remote::Response
|
132
|
+
# @private
|
94
133
|
def error_message
|
95
134
|
val = value
|
96
135
|
|