selenium-webdriver 2.13.0 → 2.14.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.
@@ -89,7 +89,7 @@ module Selenium
89
89
  raise ArgumentError, "preference values must be plain strings: #{key.inspect} => #{value.inspect}"
90
90
  end
91
91
 
92
- value = value.to_json
92
+ value = MultiJson.encode(value)
93
93
  when TrueClass, FalseClass, Integer, Float
94
94
  value = value.to_s
95
95
  else
@@ -1,6 +1,10 @@
1
1
  module Selenium
2
2
  module WebDriver
3
3
  module IPhone
4
+ #
5
+ # @api private
6
+ #
7
+
4
8
  class Bridge < Remote::Bridge
5
9
 
6
10
  DEFAULT_URL = "http://#{Platform.localhost}:3001/hub/"
@@ -85,7 +85,15 @@ module Selenium
85
85
 
86
86
  def iphone(opts = {})
87
87
  new({
88
- :browser_name => "iphone",
88
+ :browser_name => "iPhone",
89
+ :platform => :mac,
90
+ :javascript_enabled => true
91
+ }.merge(opts))
92
+ end
93
+
94
+ def ipad(opts = {})
95
+ new({
96
+ :browser_name => "iPad",
89
97
  :platform => :mac,
90
98
  :javascript_enabled => true
91
99
  }.merge(opts))
@@ -206,7 +214,7 @@ module Selenium
206
214
  end
207
215
 
208
216
  def to_json(*args)
209
- as_json.to_json(*args)
217
+ MultiJson.encode as_json
210
218
  end
211
219
 
212
220
  def ==(other)
@@ -23,7 +23,7 @@ module Selenium
23
23
  headers = DEFAULT_HEADERS.dup
24
24
 
25
25
  if command_hash
26
- payload = command_hash.to_json
26
+ payload = MultiJson.encode(command_hash)
27
27
  headers["Content-Type"] = "#{CONTENT_TYPE}; charset=utf-8"
28
28
  headers["Content-Length"] = payload.bytesize.to_s if [:post, :put].include?(verb)
29
29
 
@@ -55,7 +55,7 @@ module Selenium
55
55
 
56
56
  if content_type.include? CONTENT_TYPE
57
57
  raise Error::WebDriverError, "empty body: #{content_type.inspect} (#{code})\n#{body}" if body.empty?
58
- Response.new(code, JSON.parse(body))
58
+ Response.new(code, MultiJson.decode(body))
59
59
  elsif code == 204
60
60
  Response.new(code)
61
61
  else
@@ -1,3 +1,4 @@
1
1
  require 'selenium/webdriver/support/event_firing_bridge'
2
2
  require 'selenium/webdriver/support/abstract_event_listener'
3
- require 'selenium/webdriver/support/block_event_listener'
3
+ require 'selenium/webdriver/support/block_event_listener'
4
+ require 'selenium/webdriver/support/select'
@@ -3,6 +3,10 @@ module Selenium
3
3
  module Support
4
4
  class Select
5
5
 
6
+ #
7
+ # @param [Element] element The select element to use
8
+ #
9
+
6
10
  def initialize(element)
7
11
  tag_name = element.tag_name
8
12
 
@@ -17,6 +21,8 @@ module Selenium
17
21
  #
18
22
  # Does this select element support selecting multiple options?
19
23
  #
24
+ # @return [Boolean]
25
+ #
20
26
 
21
27
  def multiple?
22
28
  @multi
@@ -25,14 +31,18 @@ module Selenium
25
31
  #
26
32
  # Get all options for this select element
27
33
  #
34
+ # @return [Array<Element>]
35
+ #
28
36
 
29
37
  def options
30
- @element.find_elements :tag_name => "option"
38
+ @element.find_elements :tag_name, 'option'
31
39
  end
32
40
 
33
41
  #
34
42
  # Get all selected options for this select element
35
43
  #
44
+ # @return [Array<Element>]
45
+ #
36
46
 
37
47
  def selected_options
38
48
  options.select { |e| e.selected? }
@@ -41,6 +51,9 @@ module Selenium
41
51
  #
42
52
  # Get the first selected option in this select element
43
53
  #
54
+ # @raise [Error::NoSuchElementError] if no options are selected
55
+ # @return [Element]
56
+ #
44
57
 
45
58
  def first_selected_option
46
59
  option = options.find { |e| e.selected? }
@@ -50,253 +63,231 @@ module Selenium
50
63
  #
51
64
  # Select options by visible text, index or value.
52
65
  #
66
+ # When selecting by :text, selects options that display text matching the argument. That is, when given "Bar" this
67
+ # would select an option like:
68
+ #
69
+ # <option value="foo">Bar</option>
70
+ #
71
+ # When slecting by :value, selects all options that have a value matching the argument. That is, when given "foo" this
72
+ # would select an option like:
73
+ #
74
+ # <option value="foo">Bar</option>
75
+ #
76
+ # When selecting by :index, selects the option at the given index. This is done by examining the "index" attribute of an
77
+ # element, and not merely by counting.
78
+ #
79
+ # @param [:text, :index, :value] how How to find the option
80
+ # @param [String] what What value to find the option by.
81
+ #
53
82
 
54
- def select(how, what)
83
+ def select_by(how, what)
55
84
  case how
56
- when :text, :index, :value
57
- raise NotImplementedError
85
+ when :text
86
+ select_by_text what
87
+ when :index
88
+ select_by_index what
89
+ when :value
90
+ select_by_value what
58
91
  else
59
92
  raise ArgumentError, "can't select options by #{how.inspect}"
60
93
  end
61
94
  end
62
95
 
63
- # /**
64
- # * Select all options that display text matching the argument. That is, when given "Bar" this
65
- # * would select an option like:
66
- # *
67
- # * &lt;option value="foo"&gt;Bar&lt;/option&gt;
68
- # *
69
- # * @param text The visible text to match against
70
- # */
71
- # public void selectByVisibleText(String text) {
72
- # // try to find the option via XPATH ...
73
- # List<WebElement> options =
74
- # element.findElements(By.xpath(".//option[normalize-space(.) = " + escapeQuotes(text) + "]"));
75
- #
76
- # boolean matched = false;
77
- # for (WebElement option : options) {
78
- # setSelected(option);
79
- # if (!isMultiple()) {
80
- # return;
81
- # }
82
- # matched = true;
83
- # }
84
- #
85
- # if (options.isEmpty() && text.contains(" ")) {
86
- # String subStringWithoutSpace = getLongestSubstringWithoutSpace(text);
87
- # List<WebElement> candidates;
88
- # if ("".equals(subStringWithoutSpace)) {
89
- # // hmm, text is either empty or contains only spaces - get all options ...
90
- # candidates = element.findElements(By.tagName("option"));
91
- # } else {
92
- # // get candidates via XPATH ...
93
- # candidates =
94
- # element.findElements(By.xpath(".//option[contains(., " +
95
- # escapeQuotes(subStringWithoutSpace) + ")]"));
96
- # }
97
- # for (WebElement option : candidates) {
98
- # if (text.equals(option.getText())) {
99
- # setSelected(option);
100
- # if (!isMultiple()) {
101
- # return;
102
- # }
103
- # matched = true;
104
- # }
105
- # }
106
- # }
107
- #
108
- # if (!matched) {
109
- # throw new NoSuchElementException("Cannot locate element with text: " + text);
110
- # }
111
- # }
112
- #
113
- # private String getLongestSubstringWithoutSpace(String s) {
114
- # String result = "";
115
- # StringTokenizer st = new StringTokenizer(s, " ");
116
- # while (st.hasMoreTokens()) {
117
- # String t = st.nextToken();
118
- # if (t.length() > result.length()) {
119
- # result = t;
120
- # }
121
- # }
122
- # return result;
123
- # }
124
- #
125
- # /**
126
- # * Select the option at the given index. This is done by examing the "index" attribute of an
127
- # * element, and not merely by counting.
128
- # *
129
- # * @param index The option at this index will be selected
130
- # */
131
- # public void selectByIndex(int index) {
132
- # String match = String.valueOf(index);
133
- #
134
- # boolean matched = false;
135
- # for (WebElement option : getOptions()) {
136
- # if (match.equals(option.getAttribute("index"))) {
137
- # setSelected(option);
138
- # if (!isMultiple()) {
139
- # return;
140
- # }
141
- # matched = true;
142
- # }
143
- # }
144
- # if (!matched) {
145
- # throw new NoSuchElementException("Cannot locate option with index: " + index);
146
- # }
147
- # }
148
- #
149
- # /**
150
- # * Select all options that have a value matching the argument. That is, when given "foo" this
151
- # * would select an option like:
152
- # *
153
- # * &lt;option value="foo"&gt;Bar&lt;/option&gt;
154
- # *
155
- # * @param value The value to match against
156
- # */
157
- # public void selectByValue(String value) {
158
- # StringBuilder builder = new StringBuilder(".//option[@value = ");
159
- # builder.append(escapeQuotes(value));
160
- # builder.append("]");
161
- # List<WebElement> options = element.findElements(By.xpath(builder.toString()));
162
- #
163
- # boolean matched = false;
164
- # for (WebElement option : options) {
165
- # setSelected(option);
166
- # if (!isMultiple()) {
167
- # return;
168
- # }
169
- # matched = true;
170
- # }
171
- #
172
- # if (!matched) {
173
- # throw new NoSuchElementException("Cannot locate option with value: " + value);
174
- # }
175
- # }
176
- #
177
-
178
- #
179
- # Clear all selected entries. Only valid if the element supports multiple selections.
96
+ #
97
+ # Deselect options by visible text, index or value.
98
+ #
99
+ # @param [:text, :index, :value] how How to find the option
100
+ # @param [String] what What value to find the option by.
101
+ #
102
+ # @see Select#select_by
103
+ #
104
+
105
+ def deselect_by(how, what)
106
+ case how
107
+ when :text
108
+ deselect_by_text what
109
+ when :value
110
+ deselect_by_value what
111
+ when :index
112
+ deselect_by_index what
113
+ else
114
+ raise ArgumentError, "can't deselect options by #{how.inspect}"
115
+ end
116
+ end
117
+
118
+ #
119
+ # Select all unselected options. Only valid if the element supports multiple selections.
120
+ #
121
+ # @raise [Error::UnsupportedOperationError] if the element does not support multiple selections.
122
+ #
123
+
124
+ def select_all
125
+ unless multiple?
126
+ raise Error::UnsupportedOperationError, 'you may only select all options of a multi-select'
127
+ end
128
+
129
+ options.each { |e| select_option e }
130
+ end
131
+
132
+ #
133
+ # Deselect all selected options. Only valid if the element supports multiple selections.
134
+ #
135
+ # @raise [Error::UnsupportedOperationError] if the element does not support multiple selections.
180
136
  #
181
137
 
182
138
  def deselect_all
183
139
  unless multiple?
184
140
  raise Error::UnsupportedOperationError, 'you may only deselect all options of a multi-select'
185
141
  end
186
-
142
+
187
143
  options.each { |e| deselect_option e }
188
144
  end
189
-
190
- #
191
- # Deselect options by visible text, index or value.
192
- #
193
-
194
- def deselect(how, what)
195
- case how
196
- when :value, :index, :text
197
- raise NotImplementedError
198
- else
199
- raise ArgumentError, "can't deselect options by #{how.inspect}"
145
+
146
+ private
147
+
148
+ def select_by_text(text)
149
+ opts = find_by_text text
150
+
151
+ if opts.empty?
152
+ raise Error::NoSuchElementError, "cannot locate element with text: #{text.inspect}"
200
153
  end
154
+
155
+ select_options opts
201
156
  end
202
-
203
-
204
- #
205
- # /**
206
- # * Deselect all options that have a value matching the argument. That is, when given "foo" this
207
- # * would deselect an option like:
208
- # *
209
- # * &lt;option value="foo"&gt;Bar&lt;/option&gt;
210
- # *
211
- # * @param value The value to match against
212
- # */
213
- # public void deselectByValue(String value) {
214
- # StringBuilder builder = new StringBuilder(".//option[@value = ");
215
- # builder.append(escapeQuotes(value));
216
- # builder.append("]");
217
- # List<WebElement> options = element.findElements(By.xpath(builder.toString()));
218
- # for (WebElement option : options) {
219
- # if (option.isSelected()) {
220
- # option.click();
221
- # }
222
- # }
223
- # }
224
- #
225
- # /**
226
- # * Deselect the option at the given index. This is done by examing the "index" attribute of an
227
- # * element, and not merely by counting.
228
- # *
229
- # * @param index The option at this index will be deselected
230
- # */
231
- # public void deselectByIndex(int index) {
232
- # String match = String.valueOf(index);
233
- #
234
- # for (WebElement option : getOptions()) {
235
- # if (match.equals(option.getAttribute("index")) && option.isSelected()) {
236
- # option.click();
237
- # }
238
- # }
239
- # }
240
- #
241
- # /**
242
- # * Deselect all options that display text matching the argument. That is, when given "Bar" this
243
- # * would deselect an option like:
244
- # *
245
- # * &lt;option value="foo"&gt;Bar&lt;/option&gt;
246
- # *
247
- # * @param text The visible text to match against
248
- # */
249
- # public void deselectByVisibleText(String text) {
250
- # StringBuilder builder = new StringBuilder(".//option[normalize-space(.) = ");
251
- # builder.append(escapeQuotes(text));
252
- # builder.append("]");
253
- # List<WebElement> options = element.findElements(By.xpath(builder.toString()));
254
- # for (WebElement option : options) {
255
- # if (option.isSelected()) {
256
- # option.click();
257
- # }
258
- # }
259
- # }
260
- #
261
- # protected String escapeQuotes(String toEscape) {
262
- # // Convert strings with both quotes and ticks into: foo'"bar -> concat("foo'", '"', "bar")
263
- # if (toEscape.indexOf("\"") > -1 && toEscape.indexOf("'") > -1) {
264
- # boolean quoteIsLast = false;
265
- # if (toEscape.indexOf("\"") == toEscape.length() - 1) {
266
- # quoteIsLast = true;
267
- # }
268
- # String[] substrings = toEscape.split("\"");
269
- #
270
- # StringBuilder quoted = new StringBuilder("concat(");
271
- # for (int i = 0; i < substrings.length; i++) {
272
- # quoted.append("\"").append(substrings[i]).append("\"");
273
- # quoted
274
- # .append(((i == substrings.length - 1) ? (quoteIsLast ? ", '\"')" : ")") : ", '\"', "));
275
- # }
276
- # return quoted.toString();
277
- # }
278
- #
279
- # // Escape string with just a quote into being single quoted: f"oo -> 'f"oo'
280
- # if (toEscape.indexOf("\"") > -1) {
281
- # return String.format("'%s'", toEscape);
282
- # }
283
- #
284
- # // Otherwise return the quoted string
285
- # return String.format("\"%s\"", toEscape);
286
- # }
287
- #
288
-
157
+
158
+ def select_by_index(index)
159
+ opts = find_by_index index
160
+
161
+ if opts.empty?
162
+ raise Error::NoSuchElementError, "cannot locate element with index: #{index.inspect}"
163
+ end
164
+
165
+ select_options opts
166
+ end
167
+
168
+ def select_by_value(value)
169
+ opts = find_by_value value
170
+
171
+ if opts.empty?
172
+ raise Error::NoSuchElementError, "cannot locate option with value: #{value.inspect}"
173
+ end
174
+
175
+ select_options opts
176
+ end
177
+
178
+ def deselect_by_text(text)
179
+ opts = find_by_text text
180
+
181
+ if opts.empty?
182
+ raise Error::NoSuchElementError, "cannot locate element with text: #{text.inspect}"
183
+ end
184
+
185
+ deselect_options opts
186
+ end
187
+
188
+ def deselect_by_value(value)
189
+ opts = find_by_value value
190
+
191
+ if opts.empty?
192
+ raise Error::NoSuchElementError, "cannot locate option with value: #{value.inspect}"
193
+ end
194
+
195
+ deselect_options opts
196
+ end
197
+
198
+ def deselect_by_index(index)
199
+ opts = find_by_index index
200
+
201
+ if opts.empty?
202
+ raise Error::NoSuchElementError, "cannot locate option with index: #{index}"
203
+ end
204
+
205
+ deselect_options opts
206
+ end
207
+
289
208
  private
290
-
291
- def select_option(opt)
292
- opt.click unless opt.selected?
209
+
210
+ def select_option(option)
211
+ option.click unless option.selected?
212
+ end
213
+
214
+ def deselect_option(option)
215
+ option.click if option.selected?
293
216
  end
294
-
295
- def deselect_option(opt)
296
- opt.click if opt.selected?
217
+
218
+ def select_options(opts)
219
+ if multiple?
220
+ opts.each { |o| select_option o }
221
+ else
222
+ select_option opts.first
223
+ end
224
+ end
225
+
226
+ def deselect_options(opts)
227
+ if multiple?
228
+ opts.each { |o| deselect_option o }
229
+ else
230
+ deselect_option opts.first
231
+ end
297
232
  end
298
233
 
299
- end
234
+ def find_by_text(text)
235
+ xpath = ".//option[normalize-space(.) = #{Escaper.escape text}]"
236
+ opts = @element.find_elements(:xpath, xpath)
237
+
238
+ if opts.empty? && text =~ /\s+/
239
+ longest_word = text.split(/\s+/).max_by { |item| item.length }
240
+
241
+ if longest_word.empty?
242
+ candidates = options
243
+ else
244
+ xpath = ".//option[contains(., #{Escaper.escape longest_word})]"
245
+ candidates = @element.find_elements(:xpath, xpath)
246
+ end
247
+
248
+ if multiple?
249
+ candidates.select { |option| text == option.text }
250
+ else
251
+ Array(candidates.find { |option| text == option.text })
252
+ end
253
+ else
254
+ opts
255
+ end
256
+ end
257
+
258
+ def find_by_index(index)
259
+ index = index.to_s
260
+ options.select { |option| option.attribute(:index) == index }
261
+ end
262
+
263
+ def find_by_value(value)
264
+ @element.find_elements(:xpath, ".//option[@value = #{Escaper.escape value}]")
265
+ end
266
+
267
+ #
268
+ # @api private
269
+ #
270
+
271
+ module Escaper
272
+ def self.escape(str)
273
+ if str.include?('"') && str.include?("'")
274
+ parts = str.split('"', -1).map { |part| %{"#{part}"} }
275
+
276
+ quoted = parts.join(%{, '"', }).
277
+ gsub(/^"", |, ""$/, '')
278
+
279
+ "concat(#{quoted})"
280
+ elsif str.include?('"')
281
+ # escape string with just a quote into being single quoted: f"oo -> 'f"oo'
282
+ "'#{str}'"
283
+ else
284
+ # otherwise return the quoted string
285
+ %{"#{str}"}
286
+ end
287
+ end
288
+ end # Escaper
289
+
290
+ end # Select
300
291
  end
301
292
  end
302
293
  end