watir 6.7.3 → 6.8.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.travis.yml +2 -0
- data/CHANGES.md +11 -0
- data/lib/watir.rb +4 -1
- data/lib/watir/adjacent.rb +1 -1
- data/lib/watir/browser.rb +5 -3
- data/lib/watir/capabilities.rb +1 -0
- data/lib/watir/container.rb +1 -1
- data/lib/watir/elements/element.rb +31 -98
- data/lib/watir/elements/file_field.rb +1 -1
- data/lib/watir/elements/iframe.rb +1 -1
- data/lib/watir/elements/image.rb +1 -5
- data/lib/watir/elements/input.rb +15 -0
- data/lib/watir/elements/radio.rb +17 -0
- data/lib/watir/elements/select.rb +67 -20
- data/lib/watir/js_execution.rb +141 -0
- data/lib/watir/js_snippets.rb +16 -0
- data/lib/watir/js_snippets/backgroundColor.js +7 -0
- data/lib/watir/{atoms → js_snippets}/fireEvent.js +2 -0
- data/lib/watir/js_snippets/focus.js +3 -0
- data/lib/watir/{atoms → js_snippets}/getInnerHtml.js +1 -0
- data/lib/watir/js_snippets/getInnerText.js +19 -0
- data/lib/watir/{atoms → js_snippets}/getOuterHtml.js +2 -0
- data/lib/watir/js_snippets/getTextContent.js +19 -0
- data/lib/watir/js_snippets/isImageLoaded.js +3 -0
- data/lib/watir/js_snippets/selectOptionsLabel.js +10 -0
- data/lib/watir/js_snippets/selectOptionsText.js +10 -0
- data/lib/watir/js_snippets/selectOptionsValue.js +10 -0
- data/lib/watir/{atoms → js_snippets}/selectText.js +3 -0
- data/lib/watir/js_snippets/selectedOptions.js +11 -0
- data/lib/watir/js_snippets/setValue.js +3 -0
- data/lib/watir/locators/element/locator.rb +24 -10
- data/lib/watir/radio_set.rb +231 -0
- data/lib/watir/user_editable.rb +16 -2
- data/lib/watirspec/remote_server.rb +2 -1
- data/spec/browser_spec.rb +8 -2
- data/spec/spec_helper.rb +1 -0
- data/spec/watirspec/elements/div_spec.rb +22 -0
- data/spec/watirspec/elements/divs_spec.rb +1 -1
- data/spec/watirspec/elements/element_spec.rb +24 -7
- data/spec/watirspec/elements/labels_spec.rb +1 -1
- data/spec/watirspec/elements/radio_spec.rb +17 -3
- data/spec/watirspec/elements/radios_spec.rb +1 -1
- data/spec/watirspec/elements/select_list_spec.rb +167 -65
- data/spec/watirspec/elements/text_field_spec.rb +36 -0
- data/spec/watirspec/html/forms_with_input_elements.html +4 -2
- data/spec/watirspec/html/non_control_elements.html +1 -1
- data/spec/watirspec/radio_set_spec.rb +340 -0
- data/spec/watirspec_helper.rb +14 -1
- data/support/doctest_helper.rb +11 -8
- data/watir.gemspec +2 -2
- metadata +30 -11
- data/lib/watir/atoms.rb +0 -22
- data/lib/watir/atoms/README +0 -3
- 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
|
@@ -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==
|
@@ -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);}
|
@@ -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,"&"));a.indexOf("<")!=-1&&(a=a.replace(ia,"<"));a.indexOf(">")!=-1&&(a=a.replace(ja,">"));a.indexOf('"')!=-1&&(a=a.replace(ka,"""));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}
|
@@ -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 =
|
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 =
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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 =
|
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 =
|
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
|
-
|
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
|