watir 6.7.3 → 6.8.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (55) hide show
  1. checksums.yaml +4 -4
  2. data/.travis.yml +2 -0
  3. data/CHANGES.md +11 -0
  4. data/lib/watir.rb +4 -1
  5. data/lib/watir/adjacent.rb +1 -1
  6. data/lib/watir/browser.rb +5 -3
  7. data/lib/watir/capabilities.rb +1 -0
  8. data/lib/watir/container.rb +1 -1
  9. data/lib/watir/elements/element.rb +31 -98
  10. data/lib/watir/elements/file_field.rb +1 -1
  11. data/lib/watir/elements/iframe.rb +1 -1
  12. data/lib/watir/elements/image.rb +1 -5
  13. data/lib/watir/elements/input.rb +15 -0
  14. data/lib/watir/elements/radio.rb +17 -0
  15. data/lib/watir/elements/select.rb +67 -20
  16. data/lib/watir/js_execution.rb +141 -0
  17. data/lib/watir/js_snippets.rb +16 -0
  18. data/lib/watir/js_snippets/backgroundColor.js +7 -0
  19. data/lib/watir/{atoms → js_snippets}/fireEvent.js +2 -0
  20. data/lib/watir/js_snippets/focus.js +3 -0
  21. data/lib/watir/{atoms → js_snippets}/getInnerHtml.js +1 -0
  22. data/lib/watir/js_snippets/getInnerText.js +19 -0
  23. data/lib/watir/{atoms → js_snippets}/getOuterHtml.js +2 -0
  24. data/lib/watir/js_snippets/getTextContent.js +19 -0
  25. data/lib/watir/js_snippets/isImageLoaded.js +3 -0
  26. data/lib/watir/js_snippets/selectOptionsLabel.js +10 -0
  27. data/lib/watir/js_snippets/selectOptionsText.js +10 -0
  28. data/lib/watir/js_snippets/selectOptionsValue.js +10 -0
  29. data/lib/watir/{atoms → js_snippets}/selectText.js +3 -0
  30. data/lib/watir/js_snippets/selectedOptions.js +11 -0
  31. data/lib/watir/js_snippets/setValue.js +3 -0
  32. data/lib/watir/locators/element/locator.rb +24 -10
  33. data/lib/watir/radio_set.rb +231 -0
  34. data/lib/watir/user_editable.rb +16 -2
  35. data/lib/watirspec/remote_server.rb +2 -1
  36. data/spec/browser_spec.rb +8 -2
  37. data/spec/spec_helper.rb +1 -0
  38. data/spec/watirspec/elements/div_spec.rb +22 -0
  39. data/spec/watirspec/elements/divs_spec.rb +1 -1
  40. data/spec/watirspec/elements/element_spec.rb +24 -7
  41. data/spec/watirspec/elements/labels_spec.rb +1 -1
  42. data/spec/watirspec/elements/radio_spec.rb +17 -3
  43. data/spec/watirspec/elements/radios_spec.rb +1 -1
  44. data/spec/watirspec/elements/select_list_spec.rb +167 -65
  45. data/spec/watirspec/elements/text_field_spec.rb +36 -0
  46. data/spec/watirspec/html/forms_with_input_elements.html +4 -2
  47. data/spec/watirspec/html/non_control_elements.html +1 -1
  48. data/spec/watirspec/radio_set_spec.rb +340 -0
  49. data/spec/watirspec_helper.rb +14 -1
  50. data/support/doctest_helper.rb +11 -8
  51. data/watir.gemspec +2 -2
  52. metadata +30 -11
  53. data/lib/watir/atoms.rb +0 -22
  54. data/lib/watir/atoms/README +0 -3
  55. data/lib/watir/extensions/select_text.rb +0 -11
@@ -0,0 +1,141 @@
1
+ module Watir
2
+ module JSExecution
3
+
4
+ #
5
+ # Delegates script execution to Browser or IFrame.
6
+ #
7
+ def execute_script(script, *args)
8
+ @query_scope.execute_script(script, *args)
9
+ end
10
+
11
+ #
12
+ # Simulates JavaScript events on element.
13
+ # Note that you may omit "on" from event name.
14
+ #
15
+ # @example
16
+ # browser.button(name: "new_user_button").fire_event :click
17
+ # browser.button(name: "new_user_button").fire_event "mousemove"
18
+ # browser.button(name: "new_user_button").fire_event "onmouseover"
19
+ #
20
+ # @param [String, Symbol] event_name
21
+ #
22
+
23
+ def fire_event(event_name)
24
+ event_name = event_name.to_s.sub(/^on/, '').downcase
25
+
26
+ element_call { execute_js :fireEvent, @element, event_name }
27
+ end
28
+
29
+ #
30
+ # Flashes (change background color to a new color and back a few times) element.
31
+ #
32
+ # @example
33
+ # browser.li(id: 'non_link_1').flash
34
+ # browser.li(id: 'non_link_1').flash(color: "green", flashes: 3, delay: 0.05)
35
+ # browser.li(id: 'non_link_1').flash(color: "yellow")
36
+ # browser.li(id: 'non_link_1').flash(flashes: 4)
37
+ # browser.li(id: 'non_link_1').flash(delay: 0.1)
38
+ #
39
+ # @param [String] color what color to flash with
40
+ # @param [Integer] flashes number of times element should be flashed
41
+ # @param [Integer, Float] delay how long to wait between flashes
42
+ #
43
+ # @return [Watir::Element]
44
+ #
45
+
46
+ def flash(color: 'red', flashes: 10, delay: 0)
47
+ background_color = style("backgroundColor")
48
+ element_color = element_call { execute_js(:backgroundColor, @element) }.strip
49
+
50
+ flashes.times do |n|
51
+ nextcolor = n.even? ? color : background_color
52
+ element_call { execute_js(:backgroundColor, @element, nextcolor) }
53
+ sleep(delay)
54
+ end
55
+
56
+ element_call { execute_js(:backgroundColor, @element, element_color) }
57
+
58
+ self
59
+ end
60
+
61
+ #
62
+ # Focuses element.
63
+ # Note that Firefox queues focus events until the window actually has focus.
64
+ #
65
+ # @see http://code.google.com/p/selenium/issues/detail?id=157
66
+ #
67
+
68
+ def focus
69
+ element_call { execute_js(:focus, @element) }
70
+ end
71
+
72
+ #
73
+ # Returns inner HTML code of element.
74
+ #
75
+ # @example
76
+ # browser.div(id: 'shown').inner_html
77
+ # #=> "<div id=\"hidden\" style=\"display: none;\">Not shown</div><div>Not hidden</div>"
78
+ #
79
+ # @return [String]
80
+ #
81
+
82
+ def inner_html
83
+ element_call { execute_js(:getInnerHtml, @element) }.strip
84
+ end
85
+
86
+ #
87
+ # Returns inner Text code of element.
88
+ #
89
+ # @example
90
+ # browser.div(id: 'shown').inner_text
91
+ # #=> "Not hidden"
92
+ #
93
+ # @return [String]
94
+ #
95
+
96
+ def inner_text
97
+ element_call { execute_js(:getInnerText, @element) }.strip
98
+ end
99
+
100
+ #
101
+ # Returns outer (inner + element itself) HTML code of element.
102
+ #
103
+ # @example
104
+ # browser.div(id: 'shown').outer_html
105
+ # #=> "<div id=\"shown\"><div id=\"hidden\" style=\"display: none;\">Not shown</div><div>Not hidden</div></div>"
106
+ #
107
+ # @return [String]
108
+ #
109
+
110
+ def outer_html
111
+ element_call { execute_js(:getOuterHtml, @element) }.strip
112
+ end
113
+ alias_method :html, :outer_html
114
+
115
+ #
116
+ # Returns text content of element.
117
+ #
118
+ # @example
119
+ # browser.div(id: 'shown').text_content
120
+ # #=> "Not shownNot hidden"
121
+ #
122
+ # @return [String]
123
+ #
124
+
125
+ def text_content
126
+ element_call { execute_js(:getTextContent, @element) }.strip
127
+ end
128
+
129
+ #
130
+ # Selects text on page (as if dragging clicked mouse across provided text).
131
+ #
132
+ # @example
133
+ # browser.li(id: 'non_link_1').select_text('Non-link')
134
+ #
135
+
136
+ def select_text(str)
137
+ element_call { execute_js :selectText, @element, str }
138
+ end
139
+
140
+ end # JSExecution
141
+ end # Watir
@@ -0,0 +1,16 @@
1
+ module Watir
2
+ module JSSnippets
3
+
4
+ private
5
+
6
+ def execute_js(function_name, *arguments)
7
+ file = File.expand_path("../js_snippets/#{function_name}.js", __FILE__)
8
+ raise Watir::Error, "Can not excute script as #{function_name}.js does not exist" unless File.exist?(file)
9
+
10
+ js = File.read(file)
11
+ script = "return (#{js}).apply(null, arguments)"
12
+ @query_scope.execute_script(script, *arguments)
13
+ end
14
+
15
+ end # JSSnippets
16
+ end # Watir
@@ -0,0 +1,7 @@
1
+ function(){
2
+ if(arguments[1]) {
3
+ arguments[0].style.backgroundColor = arguments[1];
4
+ } else {
5
+ return arguments[0].style.backgroundColor;
6
+ }
7
+ }
@@ -11,6 +11,8 @@
11
11
  // See the License for the specific language governing permissions and
12
12
  // limitations under the License.
13
13
 
14
+ // This code was built by the Selenium code base
15
+ // See https://github.com/SeleniumHQ/selenium/tree/master/javascript/watir-atoms
14
16
 
15
17
  function(){return function(){var l=this;
16
18
  function m(a){var c=typeof a;if(c=="object")if(a){if(a instanceof Array)return"array";else if(a instanceof Object)return c;var b=Object.prototype.toString.call(a);if(b=="[object Window]")return"object";if(b=="[object Array]"||typeof a.length=="number"&&typeof a.splice!="undefined"&&typeof a.propertyIsEnumerable!="undefined"&&!a.propertyIsEnumerable("splice"))return"array";if(b=="[object Function]"||typeof a.call!="undefined"&&typeof a.propertyIsEnumerable!="undefined"&&!a.propertyIsEnumerable("call"))return"function"}else return"null";else if(c==
@@ -0,0 +1,3 @@
1
+ function(){
2
+ return arguments[0].focus();
3
+ }
@@ -11,6 +11,7 @@
11
11
  // See the License for the specific language governing permissions and
12
12
  // limitations under the License.
13
13
 
14
+ // This code is a modification getOuterHtml.js which was built by the Selenium code base
14
15
 
15
16
  function(){return function(){var d=this;function e(a,b){function c(){}c.prototype=b.prototype;a.b=b.prototype;a.prototype=new c};function f(a){this.stack=Error().stack||"";if(a)this.message=String(a)}e(f,Error);function i(a){for(var b=1;b<arguments.length;b++){var c=String(arguments[b]).replace(/\$/g,"$$$$");a=a.replace(/\%s/,c)}return a}
16
17
  function j(a,b){var c=0,A=String(a).replace(/^[\s\xa0]+|[\s\xa0]+$/g,"").split("."),B=String(b).replace(/^[\s\xa0]+|[\s\xa0]+$/g,"").split("."),H=Math.max(A.length,B.length);for(var l=0;c==0&&l<H;l++){var I=A[l]||"",J=B[l]||"",K=RegExp("(\\d*)(\\D*)","g"),L=RegExp("(\\d*)(\\D*)","g");do{var g=K.exec(I)||["","",""],h=L.exec(J)||["","",""];if(g[0].length==0&&h[0].length==0)break;c=k(g[1].length==0?0:parseInt(g[1],10),h[1].length==0?0:parseInt(h[1],10))||k(g[2].length==0,h[2].length==0)||k(g[2],h[2])}while(c==
@@ -0,0 +1,19 @@
1
+ // Copyright 2011 Software Freedom Conservatory
2
+ // Licensed under the Apache License, Version 2.0 (the "License");
3
+ // you may not use this file except in compliance with the License.
4
+ // You may obtain a copy of the License at
5
+ //
6
+ // http://www.apache.org/licenses/LICENSE-2.0
7
+ //
8
+ // Unless required by applicable law or agreed to in writing, software
9
+ // distributed under the License is distributed on an "AS IS" BASIS,
10
+ // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11
+ // See the License for the specific language governing permissions and
12
+ // limitations under the License.
13
+
14
+ // This code is a modification getOuterHtml.js which was built by the Selenium code base
15
+
16
+ function(){return function(){var d=this;function e(a,b){function c(){}c.prototype=b.prototype;a.b=b.prototype;a.prototype=new c};function f(a){this.stack=Error().stack||"";if(a)this.message=String(a)}e(f,Error);function i(a){for(var b=1;b<arguments.length;b++){var c=String(arguments[b]).replace(/\$/g,"$$$$");a=a.replace(/\%s/,c)}return a}
17
+ function j(a,b){var c=0,A=String(a).replace(/^[\s\xa0]+|[\s\xa0]+$/g,"").split("."),B=String(b).replace(/^[\s\xa0]+|[\s\xa0]+$/g,"").split("."),H=Math.max(A.length,B.length);for(var l=0;c==0&&l<H;l++){var I=A[l]||"",J=B[l]||"",K=RegExp("(\\d*)(\\D*)","g"),L=RegExp("(\\d*)(\\D*)","g");do{var g=K.exec(I)||["","",""],h=L.exec(J)||["","",""];if(g[0].length==0&&h[0].length==0)break;c=k(g[1].length==0?0:parseInt(g[1],10),h[1].length==0?0:parseInt(h[1],10))||k(g[2].length==0,h[2].length==0)||k(g[2],h[2])}while(c==
18
+ 0)}return c}function k(a,b){if(a<b)return-1;else if(a>b)return 1;return 0};e(function(a,b){b.unshift(a);f.call(this,i.apply(null,b));b.shift();this.a=a},f);var m,n,o,p;function q(){return d.navigator?d.navigator.userAgent:null}p=o=n=m=false;var r;if(r=q()){var s=d.navigator;m=r.indexOf("Opera")==0;n=!m&&r.indexOf("MSIE")!=-1;o=!m&&r.indexOf("WebKit")!=-1;p=!m&&!o&&s.product=="Gecko"}var t=n,u=p,v=o,w;
19
+ a:{var x="",y;if(m&&d.opera){var z=d.opera.version;x=typeof z=="function"?z():z}else{if(u)y=/rv\:([^\);]+)(\)|;)/;else if(t)y=/MSIE\s+([^\);]+)(\)|;)/;else if(v)y=/WebKit\/(\S+)/;if(y){var C=y.exec(q());x=C?C[1]:""}}if(t){var D,E=d.document;D=E?E.documentMode:undefined;if(D>parseFloat(x)){w=String(D);break a}}w=x}var F={};!t||F["9"]||(F["9"]=j(w,"9")>=0);t&&(F["9"]||(F["9"]=j(w,"9")>=0));function G(a){if("innerText"in a)return a.innerText;else{var b=(a.nodeType==9?a:a.ownerDocument||a.document).createElement("div");b.appendChild(a.cloneNode(true));return b.innerText}}var M="_".split("."),N=d;!(M[0]in N)&&N.execScript&&N.execScript("var "+M[0]);for(var O;M.length&&(O=M.shift());)if(!M.length&&G!==undefined)N[O]=G;else N=N[O]?N[O]:N[O]={};; return this._.apply(null,arguments);}.apply({navigator:typeof window!='undefined'?window.navigator:null}, arguments);}
@@ -11,6 +11,8 @@
11
11
  // See the License for the specific language governing permissions and
12
12
  // limitations under the License.
13
13
 
14
+ // This code was built by the Selenium code base
15
+ // See https://github.com/SeleniumHQ/selenium/tree/master/javascript/watir-atoms
14
16
 
15
17
  function(){return function(){var d=this;function e(a,b){function c(){}c.prototype=b.prototype;a.b=b.prototype;a.prototype=new c};function f(a){this.stack=Error().stack||"";if(a)this.message=String(a)}e(f,Error);function i(a){for(var b=1;b<arguments.length;b++){var c=String(arguments[b]).replace(/\$/g,"$$$$");a=a.replace(/\%s/,c)}return a}
16
18
  function j(a,b){var c=0,A=String(a).replace(/^[\s\xa0]+|[\s\xa0]+$/g,"").split("."),B=String(b).replace(/^[\s\xa0]+|[\s\xa0]+$/g,"").split("."),H=Math.max(A.length,B.length);for(var l=0;c==0&&l<H;l++){var I=A[l]||"",J=B[l]||"",K=RegExp("(\\d*)(\\D*)","g"),L=RegExp("(\\d*)(\\D*)","g");do{var g=K.exec(I)||["","",""],h=L.exec(J)||["","",""];if(g[0].length==0&&h[0].length==0)break;c=k(g[1].length==0?0:parseInt(g[1],10),h[1].length==0?0:parseInt(h[1],10))||k(g[2].length==0,h[2].length==0)||k(g[2],h[2])}while(c==
@@ -0,0 +1,19 @@
1
+ // Copyright 2011 Software Freedom Conservatory
2
+ // Licensed under the Apache License, Version 2.0 (the "License");
3
+ // you may not use this file except in compliance with the License.
4
+ // You may obtain a copy of the License at
5
+ //
6
+ // http://www.apache.org/licenses/LICENSE-2.0
7
+ //
8
+ // Unless required by applicable law or agreed to in writing, software
9
+ // distributed under the License is distributed on an "AS IS" BASIS,
10
+ // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11
+ // See the License for the specific language governing permissions and
12
+ // limitations under the License.
13
+
14
+ // This code is a modification getOuterHtml.js which was built by the Selenium code base
15
+
16
+ function(){return function(){var d=this;function e(a,b){function c(){}c.prototype=b.prototype;a.b=b.prototype;a.prototype=new c};function f(a){this.stack=Error().stack||"";if(a)this.message=String(a)}e(f,Error);function i(a){for(var b=1;b<arguments.length;b++){var c=String(arguments[b]).replace(/\$/g,"$$$$");a=a.replace(/\%s/,c)}return a}
17
+ function j(a,b){var c=0,A=String(a).replace(/^[\s\xa0]+|[\s\xa0]+$/g,"").split("."),B=String(b).replace(/^[\s\xa0]+|[\s\xa0]+$/g,"").split("."),H=Math.max(A.length,B.length);for(var l=0;c==0&&l<H;l++){var I=A[l]||"",J=B[l]||"",K=RegExp("(\\d*)(\\D*)","g"),L=RegExp("(\\d*)(\\D*)","g");do{var g=K.exec(I)||["","",""],h=L.exec(J)||["","",""];if(g[0].length==0&&h[0].length==0)break;c=k(g[1].length==0?0:parseInt(g[1],10),h[1].length==0?0:parseInt(h[1],10))||k(g[2].length==0,h[2].length==0)||k(g[2],h[2])}while(c==
18
+ 0)}return c}function k(a,b){if(a<b)return-1;else if(a>b)return 1;return 0};e(function(a,b){b.unshift(a);f.call(this,i.apply(null,b));b.shift();this.a=a},f);var m,n,o,p;function q(){return d.navigator?d.navigator.userAgent:null}p=o=n=m=false;var r;if(r=q()){var s=d.navigator;m=r.indexOf("Opera")==0;n=!m&&r.indexOf("MSIE")!=-1;o=!m&&r.indexOf("WebKit")!=-1;p=!m&&!o&&s.product=="Gecko"}var t=n,u=p,v=o,w;
19
+ a:{var x="",y;if(m&&d.opera){var z=d.opera.version;x=typeof z=="function"?z():z}else{if(u)y=/rv\:([^\);]+)(\)|;)/;else if(t)y=/MSIE\s+([^\);]+)(\)|;)/;else if(v)y=/WebKit\/(\S+)/;if(y){var C=y.exec(q());x=C?C[1]:""}}if(t){var D,E=d.document;D=E?E.documentMode:undefined;if(D>parseFloat(x)){w=String(D);break a}}w=x}var F={};!t||F["9"]||(F["9"]=j(w,"9")>=0);t&&(F["9"]||(F["9"]=j(w,"9")>=0));function G(a){if("textcontent"in a)return a.textContent;else{var b=(a.nodeType==9?a:a.ownerDocument||a.document).createElement("div");b.appendChild(a.cloneNode(true));return b.textContent}}var M="_".split("."),N=d;!(M[0]in N)&&N.execScript&&N.execScript("var "+M[0]);for(var O;M.length&&(O=M.shift());)if(!M.length&&G!==undefined)N[O]=G;else N=N[O]?N[O]:N[O]={};; return this._.apply(null,arguments);}.apply({navigator:typeof window!='undefined'?window.navigator:null}, arguments);}
@@ -0,0 +1,3 @@
1
+ function(){
2
+ return typeof arguments[0].naturalWidth != "undefined" && arguments[0].naturalWidth > 0
3
+ }
@@ -0,0 +1,10 @@
1
+ function(){
2
+ for(var i=0; i<arguments[0].options.length; i++) {
3
+ if ( arguments[0].options[i].label.match(arguments[1]) ) {
4
+ arguments[0].options[i].selected = true;
5
+ if ( arguments[2] == 'single' ) {
6
+ break;
7
+ }
8
+ }
9
+ }
10
+ }
@@ -0,0 +1,10 @@
1
+ function(){
2
+ for(var i=0; i<arguments[0].options.length; i++) {
3
+ if ( arguments[0].options[i].text.match(arguments[1]) ) {
4
+ arguments[0].options[i].selected = true;
5
+ if ( arguments[2] == 'single' ) {
6
+ break;
7
+ }
8
+ }
9
+ }
10
+ }
@@ -0,0 +1,10 @@
1
+ function(){
2
+ for(var i=0; i<arguments[0].options.length; i++) {
3
+ if ( arguments[0].options[i].value.match(arguments[1]) ) {
4
+ arguments[0].options[i].selected = true;
5
+ if ( arguments[2] == 'single' ) {
6
+ break;
7
+ }
8
+ }
9
+ }
10
+ }
@@ -11,6 +11,9 @@
11
11
  // See the License for the specific language governing permissions and
12
12
  // limitations under the License.
13
13
 
14
+ // This code was built by the Selenium code base
15
+ // See https://github.com/SeleniumHQ/selenium/tree/master/javascript/watir-atoms
16
+
14
17
  function(){return function(){function f(a){throw a;}var h=void 0,l=null;function m(a){return function(){return this[a]}}function o(a){return function(){return a}}var p,r=this;
15
18
  function s(a){var b=typeof a;if(b=="object")if(a){if(a instanceof Array)return"array";else if(a instanceof Object)return b;var c=Object.prototype.toString.call(a);if(c=="[object Window]")return"object";if(c=="[object Array]"||typeof a.length=="number"&&typeof a.splice!="undefined"&&typeof a.propertyIsEnumerable!="undefined"&&!a.propertyIsEnumerable("splice"))return"array";if(c=="[object Function]"||typeof a.call!="undefined"&&typeof a.propertyIsEnumerable!="undefined"&&!a.propertyIsEnumerable("call"))return"function"}else return"null";
16
19
  else if(b=="function"&&typeof a.call=="undefined")return"object";return b}function t(a){var b=s(a);return b=="array"||b=="object"&&typeof a.length=="number"}function u(a){return typeof a=="string"}function aa(a){a=s(a);return a=="object"||a=="array"||a=="function"}var ba="closure_uid_"+Math.floor(Math.random()*2147483648).toString(36),ca=0,da=Date.now||function(){return+new Date};function v(a,b){function c(){}c.prototype=b.prototype;a.Q=b.prototype;a.prototype=new c};function ea(a){this.stack=Error().stack||"";if(a)this.message=String(a)}v(ea,Error);ea.prototype.name="CustomError";function fa(a){for(var b=1;b<arguments.length;b++)var c=String(arguments[b]).replace(/\$/g,"$$$$"),a=a.replace(/\%s/,c);return a}function w(a){if(!ga.test(a))return a;a.indexOf("&")!=-1&&(a=a.replace(ha,"&amp;"));a.indexOf("<")!=-1&&(a=a.replace(ia,"&lt;"));a.indexOf(">")!=-1&&(a=a.replace(ja,"&gt;"));a.indexOf('"')!=-1&&(a=a.replace(ka,"&quot;"));return a}var ha=/&/g,ia=/</g,ja=/>/g,ka=/\"/g,ga=/[&<>\"]/;function la(a,b){if(a<b)return-1;else if(a>b)return 1;return 0}
@@ -0,0 +1,11 @@
1
+ function(){
2
+ var result = [];
3
+ var options = arguments[0].options;
4
+ for (var i = 0; i < options.length; i++) {
5
+ var option = options[i];
6
+ if (option.selected) {
7
+ result.push(option)
8
+ }
9
+ }
10
+ return result;
11
+ }
@@ -0,0 +1,3 @@
1
+ function(){
2
+ arguments[0].value=arguments[1]
3
+ }
@@ -69,7 +69,7 @@ module Watir
69
69
  tag_name = selector.delete(:tag_name)
70
70
  return unless selector.empty? # multiple attributes
71
71
 
72
- element = @query_scope.wd.find_element(:id, id)
72
+ element = locate_element(:id, id)
73
73
  return if tag_name && !element_validator.validate(element, {tag_name: tag_name})
74
74
 
75
75
  element
@@ -98,11 +98,11 @@ module Watir
98
98
  # could build xpath/css for selector
99
99
  if idx || !visible.nil?
100
100
  idx ||= 0
101
- elements = @query_scope.wd.find_elements(how, what)
101
+ elements = locate_elements(how, what)
102
102
  elements = elements.select { |el| visible == el.displayed? } unless visible.nil?
103
103
  elements[idx] unless elements.nil?
104
104
  else
105
- @query_scope.wd.find_element(how, what)
105
+ locate_element(how, what)
106
106
  end
107
107
  else
108
108
  # can't use xpath, probably a regexp in there
@@ -119,6 +119,7 @@ module Watir
119
119
 
120
120
  def find_all_by_one
121
121
  how, what = @selector.to_a.first
122
+ return [what] if how == :element
122
123
  selector_builder.check_type how, what
123
124
 
124
125
  if WD_FINDERS.include?(how)
@@ -138,7 +139,7 @@ module Watir
138
139
 
139
140
  how, what = selector_builder.build(selector)
140
141
  found = if how
141
- @query_scope.wd.find_elements(how, what)
142
+ locate_elements(how, what)
142
143
  else
143
144
  wd_find_by_regexp_selector(selector, :select)
144
145
  end
@@ -148,7 +149,7 @@ module Watir
148
149
 
149
150
  def wd_find_all_by(how, what)
150
151
  if what.is_a? String
151
- @query_scope.wd.find_elements(how, what)
152
+ locate_elements(how, what)
152
153
  else
153
154
  all_elements.select { |element| fetch_value(element, how) =~ what }
154
155
  end
@@ -168,19 +169,19 @@ module Watir
168
169
  end
169
170
 
170
171
  def all_elements
171
- @query_scope.wd.find_elements(xpath: ".//*")
172
+ locate_elements(:xpath, ".//*")
172
173
  end
173
174
 
174
175
  def wd_find_first_by(how, what)
175
176
  if what.is_a? String
176
- @query_scope.wd.find_element(how, what)
177
+ locate_element(how, what)
177
178
  else
178
179
  all_elements.find { |element| fetch_value(element, how) =~ what }
179
180
  end
180
181
  end
181
182
 
182
183
  def wd_find_by_regexp_selector(selector, method = :find)
183
- query_scope = @query_scope.wd
184
+ query_scope = ensure_scope_context
184
185
  rx_selector = delete_regexps_from(selector)
185
186
 
186
187
  if rx_selector.key?(:label) && selector_builder.should_use_label_element?
@@ -207,7 +208,7 @@ module Watir
207
208
  end
208
209
  end
209
210
 
210
- elements = query_scope.find_elements(how, what)
211
+ elements = locate_elements(how, what, query_scope)
211
212
  elements.__send__(method) { |el| matches_selector?(el, rx_selector) }
212
213
  end
213
214
 
@@ -225,7 +226,7 @@ module Watir
225
226
 
226
227
  def label_from_text(label_exp)
227
228
  # TODO: this won't work correctly if @wd is a sub-element
228
- @query_scope.wd.find_elements(:tag_name, 'label').find do |el|
229
+ locate_elements(:tag_name, 'label').find do |el|
229
230
  matches_selector?(el, text: label_exp)
230
231
  end
231
232
  end
@@ -251,6 +252,19 @@ module Watir
251
252
  "contains(#{lhs}, #{XpathSupport.escape(literals)})"
252
253
  end
253
254
  end
255
+
256
+ def ensure_scope_context
257
+ @query_scope.wd
258
+ end
259
+
260
+ def locate_element(how, what)
261
+ @query_scope.wd.find_element(how, what)
262
+ end
263
+
264
+ def locate_elements(how, what, scope = @query_scope.wd)
265
+ scope.find_elements(how, what)
266
+ end
267
+
254
268
  end
255
269
  end
256
270
  end
@@ -0,0 +1,231 @@
1
+ module Watir
2
+ class RadioSet
3
+ extend Forwardable
4
+ include Watir::Exception
5
+ include Enumerable
6
+
7
+ delegate [:exists?, :present?, :visible?, :browser] => :source
8
+
9
+ attr_reader :source, :frame
10
+
11
+ def initialize(query_scope, selector)
12
+ unless selector.kind_of? Hash
13
+ raise ArgumentError, "invalid argument: #{selector.inspect}"
14
+ end
15
+
16
+ @source = Radio.new(query_scope, selector)
17
+ @frame = @source.parent(tag_name: :form)
18
+ end
19
+
20
+ #
21
+ # Yields each Radio associated with this set.
22
+ #
23
+ # @example
24
+ # radio_set = browser.radio_set
25
+ # radio_set.each do |radio|
26
+ # puts radio.text
27
+ # end
28
+ #
29
+ # @yieldparam [Watir::RadioSet] element iterate through the radio buttons.
30
+ #
31
+
32
+ def each(&block)
33
+ radios.each(&block)
34
+ end
35
+
36
+ #
37
+ # Get the n'th radio button in this set
38
+ #
39
+ # @return Watir::Radio
40
+ #
41
+
42
+ def [](idx)
43
+ radios[idx]
44
+ end
45
+
46
+ #
47
+ # @return Watir::Radio
48
+ #
49
+
50
+ def radio(opt = {})
51
+ n = name
52
+ if !n.empty? && (!opt[:name] || opt[:name] == n)
53
+ frame.radio(opt.merge name: n)
54
+ elsif n.empty?
55
+ return source
56
+ else
57
+ raise Watir::Exception::UnknownObjectException, "#{opt[:name]} does not match name of RadioSet: #{n}"
58
+ end
59
+
60
+ end
61
+
62
+ #
63
+ # @return Watir::RadioCollection
64
+ #
65
+
66
+ def radios(opt = {})
67
+ n = name
68
+ if !n.empty? && (!opt[:name] || opt[:name] == n)
69
+ element_call(:wait_for_present) { frame.radios(opt.merge name: n) }
70
+ elsif n.empty?
71
+ Watir::RadioCollection.new(frame, element: source.wd)
72
+ else
73
+ raise Watir::Exception::UnknownObjectException, "#{opt[:name]} does not match name of RadioSet: #{n}"
74
+ end
75
+ end
76
+
77
+ #
78
+ # Returns true if any radio buttons in the set are enabled.
79
+ #
80
+ # @return [Boolean]
81
+ #
82
+
83
+ def enabled?
84
+ any?(&:enabled?)
85
+ end
86
+
87
+ #
88
+ # Returns true if all radio buttons in the set are disabled.
89
+ #
90
+ # @return [Boolean]
91
+ #
92
+
93
+ def disabled?
94
+ !enabled?
95
+ end
96
+
97
+ #
98
+ # Returns the name attribute for the set.
99
+ #
100
+ # @return [String]
101
+ #
102
+
103
+ def name
104
+ @name ||= source.name
105
+ end
106
+
107
+ #
108
+ # If RadioSet exists, this always returns 'radio'.
109
+ #
110
+ # @return [String]
111
+ #
112
+
113
+ def type
114
+ source.send :assert_exists
115
+ 'radio'
116
+ end
117
+
118
+ #
119
+ # Returns true if the radio set has one or more radio buttons where label matches the given value.
120
+ #
121
+ # @param [String, Regexp] str_or_rx
122
+ # @return [Boolean]
123
+ #
124
+
125
+ def include?(str_or_rx)
126
+ radio(label: str_or_rx).exist?
127
+ end
128
+
129
+ #
130
+ # Select the radio button whose value or label matches the given string.
131
+ #
132
+ # @param [String, Regexp] str_or_rx
133
+ # @raise [Watir::Exception::UnknownObjectException] if the Radio does not exist.
134
+ # @return [String] The value or text of the radio selected.
135
+ #
136
+
137
+ def select(str_or_rx)
138
+ found_by_value = radio(value: str_or_rx)
139
+ found_by_text = radio(label: str_or_rx)
140
+
141
+ if found_by_value.exist?
142
+ found_by_value.click unless found_by_value.selected?
143
+ return found_by_value.value
144
+ elsif found_by_text.exist?
145
+ found_by_text.click unless found_by_text.selected?
146
+ return found_by_text.text
147
+ else
148
+ raise UnknownObjectException, "Unable to locate radio matching #{str_or_rx.inspect}"
149
+ end
150
+ end
151
+
152
+ #
153
+ # Returns true if any of the radio button label matches the given value.
154
+ #
155
+ # @param [String, Regexp] str_or_rx
156
+ # @raise [Watir::Exception::UnknownObjectException] if the options do not exist
157
+ # @return [Boolean]
158
+ #
159
+
160
+ def selected?(str_or_rx)
161
+ found = frame.radio(label: str_or_rx)
162
+
163
+ return found.selected? if found.exist?
164
+ raise UnknownObjectException, "Unable to locate radio matching #{str_or_rx.inspect}"
165
+ end
166
+
167
+ #
168
+ # Returns the value of the selected radio button in the set.
169
+ # Returns nil if no radio is selected.
170
+ #
171
+ # @return [String, nil]
172
+ #
173
+
174
+ def value
175
+ sel = selected
176
+ sel && sel.value
177
+ end
178
+
179
+ #
180
+ # Returns the text of the selected radio button in the set.
181
+ # Returns nil if no option is selected.
182
+ #
183
+ # @return [String, nil]
184
+ #
185
+
186
+ def text
187
+ sel = selected
188
+ sel && sel.text
189
+ end
190
+
191
+ #
192
+ # Returns the selected Radio element.
193
+ # Returns nil if no radio button is selected.
194
+ #
195
+ # @return [Watir::Radio, nil]
196
+ #
197
+
198
+ def selected
199
+ find(&:selected?)
200
+ end
201
+
202
+ #
203
+ # Returns true if two elements are equal.
204
+ #
205
+ # @example
206
+ # browser.radio_set(id: 'new_user_newsletter_yes') == browser.radio_set(id: 'new_user_newsletter_no')
207
+ # #=> true
208
+ #
209
+
210
+ def ==(other)
211
+ return false unless other.kind_of?(self.class)
212
+ radios == other.radios
213
+ end
214
+ alias_method :eql?, :==
215
+
216
+ private
217
+
218
+ def element_call(*args, &blk)
219
+ source.send :element_call, *args, &blk
220
+ end
221
+ end # RadioSet
222
+
223
+ module Container
224
+ def radio_set(*args)
225
+ RadioSet.new(self, extract_selector(args).merge(tag_name: "input", type: "radio"))
226
+ end
227
+
228
+ Watir.tag_to_class[:radio_set] = RadioSet
229
+ end # Container
230
+
231
+ end # Watir