selenium-webdriver 2.13.0 → 2.14.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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