firewatir 1.6.2 → 1.6.5

Sign up to get free protection for your applications and to get access to all the features.
Files changed (85) hide show
  1. data/LICENSE +32 -0
  2. data/lib/firewatir.rb +40 -50
  3. data/lib/firewatir/container.rb +491 -534
  4. data/lib/firewatir/document.rb +239 -0
  5. data/lib/firewatir/element.rb +1365 -0
  6. data/lib/firewatir/element_collections.rb +314 -0
  7. data/lib/firewatir/elements/button.rb +15 -0
  8. data/lib/firewatir/elements/file_field.rb +29 -0
  9. data/lib/firewatir/elements/form.rb +40 -0
  10. data/lib/firewatir/elements/frame.rb +55 -0
  11. data/lib/firewatir/elements/hidden.rb +56 -0
  12. data/lib/firewatir/elements/image.rb +139 -0
  13. data/lib/firewatir/elements/input_element.rb +44 -0
  14. data/lib/firewatir/elements/link.rb +76 -0
  15. data/lib/firewatir/elements/non_control_element.rb +53 -0
  16. data/lib/firewatir/elements/non_control_elements.rb +108 -0
  17. data/lib/firewatir/elements/not_used.rb +278 -0
  18. data/lib/firewatir/elements/option.rb +131 -0
  19. data/lib/firewatir/elements/radio_check_common.rb +163 -0
  20. data/lib/firewatir/elements/select_list.rb +188 -0
  21. data/lib/firewatir/elements/table.rb +218 -0
  22. data/lib/firewatir/elements/table_cell.rb +54 -0
  23. data/lib/firewatir/elements/table_row.rb +100 -0
  24. data/lib/firewatir/elements/text_field.rb +218 -0
  25. data/lib/firewatir/exceptions.rb +10 -10
  26. data/lib/firewatir/firefox.rb +1040 -1127
  27. data/lib/firewatir/jssh_socket.rb +101 -0
  28. data/lib/firewatir/version.rb +5 -5
  29. data/unittests/attach_to_new_window_test.rb +49 -42
  30. data/unittests/bug_fixes_test.rb +195 -198
  31. data/unittests/buttons_xpath_test.rb +88 -88
  32. data/unittests/checkbox_test.rb +158 -155
  33. data/unittests/checkbox_xpath_test.rb +107 -107
  34. data/unittests/div_test.rb +275 -276
  35. data/unittests/filefield_test.rb +49 -45
  36. data/unittests/filefield_xpath_test.rb +35 -35
  37. data/unittests/form_test.rb +296 -308
  38. data/unittests/frame_test.rb +159 -152
  39. data/unittests/hidden_test.rb +85 -85
  40. data/unittests/hidden_xpath_test.rb +72 -72
  41. data/unittests/html/blankpage.html +11 -11
  42. data/unittests/html/buttons1.html +61 -61
  43. data/unittests/html/cssTest.html +42 -42
  44. data/unittests/html/div.html +72 -72
  45. data/unittests/html/fileupload.html +45 -45
  46. data/unittests/html/formTest1.html +38 -38
  47. data/unittests/html/forms2.html +45 -45
  48. data/unittests/html/frame_buttons.html +3 -3
  49. data/unittests/html/iframeTest.html +14 -14
  50. data/unittests/html/iframeTest1.html +13 -13
  51. data/unittests/html/iframeTest2.html +5 -5
  52. data/unittests/html/links1.html +42 -42
  53. data/unittests/html/nestedFrames.html +6 -6
  54. data/unittests/html/new_browser.html +1 -0
  55. data/unittests/html/new_browser_popup.html +8 -0
  56. data/unittests/html/pass.html +9 -9
  57. data/unittests/html/pre.html +27 -27
  58. data/unittests/html/redirect.html +10 -10
  59. data/unittests/html/redirect1.html +8 -8
  60. data/unittests/html/redirect2.html +8 -8
  61. data/unittests/html/redirect3.html +8 -8
  62. data/unittests/html/simple_table_columns.html +74 -74
  63. data/unittests/html/table1.html +165 -165
  64. data/unittests/html/textfields1.html +62 -62
  65. data/unittests/images_test.rb +198 -205
  66. data/unittests/images_xpath_test.rb +118 -119
  67. data/unittests/javascript_test.rb +75 -75
  68. data/unittests/links_test.rb +231 -232
  69. data/unittests/links_xpath_test.rb +79 -79
  70. data/unittests/mozilla_all_tests.rb +7 -7
  71. data/unittests/pre_test.rb +75 -76
  72. data/unittests/radios_xpath_test.rb +101 -101
  73. data/unittests/redirect_test.rb +41 -41
  74. data/unittests/selectbox_test.rb +142 -142
  75. data/unittests/selectbox_xpath_test.rb +129 -129
  76. data/unittests/setup.rb +29 -30
  77. data/unittests/table_test.rb +385 -373
  78. data/unittests/table_xpath_test.rb +185 -185
  79. data/unittests/textfields_test.rb +234 -233
  80. data/unittests/textfields_xpath_test.rb +113 -113
  81. metadata +33 -11
  82. data/lib/firewatir/MozillaBaseElement.rb +0 -1863
  83. data/lib/firewatir/htmlelements.rb +0 -1911
  84. data/unittests/iostring.rb +0 -30
  85. data/unittests/iostring_test.rb +0 -48
@@ -0,0 +1,239 @@
1
+ module FireWatir
2
+ #
3
+ # Description:
4
+ # Class for returning the document element.
5
+ #
6
+ class Document
7
+ include FireWatir::Container
8
+ @@current_level = 0
9
+
10
+ #
11
+ # Description:
12
+ # Creates new instance of Document class.
13
+ #
14
+ def initialize(container)
15
+ @length = 0
16
+ @elements = nil
17
+ @arr_elements = ""
18
+ @container = container
19
+ end
20
+
21
+ def frames
22
+ jssh_command = "var frameset = #{@container.window_var}.frames;
23
+ var elements_frames = new Array();
24
+ for(var i = 0; i < frameset.length; i++)
25
+ {
26
+ var frames = frameset[i].frames;
27
+ for(var j = 0; j < frames.length; j++)
28
+ {
29
+ elements_frames.push(frames[j].frameElement);
30
+ }
31
+ }
32
+ elements_frames.length;"
33
+
34
+ jssh_command.gsub!("\n", "")
35
+ $jssh_socket.send("#{jssh_command};\n", 0)
36
+ length = read_socket().to_i
37
+
38
+ frame_array = Array.new(length)
39
+ for i in 0..length - 1 do
40
+ frame_array[i] = Frame.new(self, :jssh_name, "elements_frames[#{i}]")
41
+ end
42
+ frame_array
43
+ end
44
+
45
+ #
46
+ # Description:
47
+ # Find all the elements in the document by querying DOM.
48
+ # Set the class variables like length and the variable name of array storing the elements in JSSH.
49
+ #
50
+ # Output:
51
+ # Array of elements.
52
+ #
53
+ def all
54
+ @arr_elements = "arr_coll_#{@@current_level}"
55
+ jssh_command = "var arr_coll_#{@@current_level}=new Array(); "
56
+
57
+ if(@container.class == FireWatir::Firefox || @container.class == Frame)
58
+ jssh_command <<"var element_collection = null; element_collection = #{@container.document_var}.getElementsByTagName(\"*\");
59
+ if(element_collection != null && typeof(element_collection) != 'undefined')
60
+ {
61
+ for (var i = 0; i < element_collection.length; i++)
62
+ {
63
+ if((element_collection[i].tagName != 'BR') && (element_collection[i].tagName != 'HR') && (element_collection[i].tagName != 'DOCTYPE') && (element_collection[i].tagName != 'META') && (typeof(element_collection[i].tagName) != 'undefined'))
64
+ arr_coll_#{@@current_level}.push(element_collection[i]);
65
+ }
66
+ }
67
+ arr_coll_#{@@current_level}.length;"
68
+ else
69
+ jssh_command <<"var element_collection = null; element_collection = #{@container.element_name}.getElementsByTagName(\"*\");
70
+ if(element_collection!= null && typeof(element_collection) != 'undefined')
71
+ {
72
+ for (var i = 0; i < element_collection.length; i++)
73
+ {
74
+ if((element_collection[i].tagName != 'BR') && (element_collection[i].tagName != 'HR') && (element_collection[i].tagName != 'DOCTYPE') && (element_collection[i].tagName != 'META') && (typeof(element_collection[i].tagName) != 'undefined'))
75
+ arr_coll_#{@@current_level}.push(element_collection[i]);
76
+ }
77
+ }
78
+ arr_coll_#{@@current_level}.length;"
79
+ end
80
+
81
+ # Remove \n that are there in the string as a result of pressing enter while formatting.
82
+ jssh_command.gsub!(/\n/, "")
83
+ #puts jssh_command
84
+ jssh_socket.send("#{jssh_command};\n", 0)
85
+ @length = read_socket().to_i;
86
+ #puts "elements length is in locate_tagged_elements is : #{@length}"
87
+
88
+ elements = nil
89
+ elements = Array.new(@length)
90
+ for i in 0..@length - 1 do
91
+ temp = Element.new("arr_coll_#{@@current_level}[#{i}]", @container)
92
+ elements[i] = temp
93
+ end
94
+ @@current_level += 1
95
+ return elements
96
+
97
+ end
98
+
99
+ #
100
+ # Description:
101
+ # Returns the count of elements in the document.
102
+ #
103
+ # Output:
104
+ # Count of elements found in the document.
105
+ #
106
+ def length
107
+ return @length
108
+ end
109
+ alias_method :size, :length
110
+
111
+ #
112
+ # Description:
113
+ # Iterates over elements in the document.
114
+ #
115
+ def each
116
+ for i in 0..@length - 1
117
+ yield Element.new("#{@arr_elements}[#{i}]", @container)
118
+ end
119
+ end
120
+
121
+ #
122
+ # Description:
123
+ # Gets the element at the nth index in the array of the elements.
124
+ #
125
+ # Input:
126
+ # n - Index of element you want to access. Index is 1 based.
127
+ #
128
+ # Output:
129
+ # Element at the nth index.
130
+ #
131
+ def [](n)
132
+ return Element.new("#{@arr_elements}[#{n-1}]", @container)
133
+ end
134
+
135
+ #
136
+ # Description:
137
+ # Get all forms available on the page.
138
+ # Used internally by Firewatir use ff.show_forms instead.
139
+ #
140
+ # Output:
141
+ # Array containing Form elements
142
+ #
143
+ def get_forms()
144
+ jssh_socket.send("var element_forms = #{@container.document_var}.forms; element_forms.length;\n", 0)
145
+ length = read_socket().to_i
146
+ forms = Array.new(length)
147
+
148
+ for i in 0..length - 1 do
149
+ forms[i] = Form.new(@container, :jssh_name, "element_forms[#{i}]")
150
+ end
151
+ return forms
152
+ end
153
+
154
+ #
155
+ # Description:
156
+ # Get all images available on the page.
157
+ # Used internally by Firewatir use ff.show_images instead.
158
+ #
159
+ # Output:
160
+ # Array containing Image elements
161
+ #
162
+ def get_images
163
+ return Images.new(@container)
164
+ end
165
+
166
+ #
167
+ # Description:
168
+ # Get all links available on the page.
169
+ # Used internally by Firewatir use ff.show_links instead.
170
+ #
171
+ # Output:
172
+ # Array containing Link elements
173
+ #
174
+ def get_links
175
+ return Links.new(@container)
176
+ end
177
+
178
+ #
179
+ # Description:
180
+ # Get all divs available on the page.
181
+ # Used internally by Firewatir use ff.show_divs instead.
182
+ #
183
+ # Output:
184
+ # Array containing Div elements
185
+ #
186
+ def get_divs
187
+ return Divs.new(@container)
188
+ end
189
+
190
+ #
191
+ # Description:
192
+ # Get all tables available on the page.
193
+ # Used internally by Firewatir use ff.show_tables instead.
194
+ #
195
+ # Output:
196
+ # Array containing Table elements
197
+ #
198
+ def get_tables
199
+ return Tables.new(@container)
200
+ end
201
+
202
+ #
203
+ # Description:
204
+ # Get all pres available on the page.
205
+ # Used internally by Firewatir use ff.show_pres instead.
206
+ #
207
+ # Output:
208
+ # Array containing Pre elements
209
+ #
210
+ def get_pres
211
+ return Pres.new(@container)
212
+ end
213
+
214
+ #
215
+ # Description:
216
+ # Get all spans available on the page.
217
+ # Used internally by Firewatir use ff.show_spans instead.
218
+ #
219
+ # Output:
220
+ # Array containing Span elements
221
+ #
222
+ def get_spans
223
+ return Spans.new(@container)
224
+ end
225
+
226
+ #
227
+ # Description:
228
+ # Get all labels available on the page.
229
+ # Used internally by Firewatir use ff.show_labels instead.
230
+ #
231
+ # Output:
232
+ # Array containing Label elements
233
+ #
234
+ def get_labels
235
+ return Labels.new(@container)
236
+ end
237
+
238
+ end # Docuemnt
239
+ end # FireWatir
@@ -0,0 +1,1365 @@
1
+ module FireWatir
2
+ # Base class for html elements.
3
+ # This is not a class that users would normally access.
4
+ class Element
5
+ include FireWatir::Container
6
+ # Number of spaces that separate the property from the value in the to_s method
7
+ TO_S_SIZE = 14
8
+
9
+ # How to get the nodes using XPath in mozilla.
10
+ ORDERED_NODE_ITERATOR_TYPE = 5
11
+ # To get the number of nodes returned by the xpath expression
12
+ NUMBER_TYPE = 1
13
+ # To get single node value
14
+ FIRST_ORDERED_NODE_TYPE = 9
15
+ # This stores the level to which we have gone finding element inside another element.
16
+ # This is just to make sure that every element has unique name in JSSH.
17
+ @@current_level = 0
18
+ # This stores the name of the element that is about to trigger an Javascript pop up.
19
+ #@@current_js_object = nil
20
+
21
+ attr_accessor :element_name
22
+ #
23
+ # Description:
24
+ # Creates new instance of element. If argument is not nil and is of type string this
25
+ # sets the element_name and element_type property of the object. These properties can
26
+ # be accessed using element_object and element_type methods respectively.
27
+ #
28
+ # Used internally by FireWatir.
29
+ #
30
+ # Input:
31
+ # element - Name of the variable with which the element is referenced in JSSh.
32
+ #
33
+ def initialize(element, container=nil)
34
+ @container = container
35
+ @element_name = element
36
+ @element_type = element_type
37
+ #puts "in initialize "
38
+ #puts caller(0)
39
+ #if(element != nil && element.class == String)
40
+ #@element_name = element
41
+ #elsif(element != nil && element.class == Element)
42
+ # @o = element
43
+ #end
44
+
45
+ #puts "@element_name is #{@element_name}"
46
+ #puts "@element_type is #{@element_type}"
47
+ end
48
+
49
+ private
50
+ def self.def_wrap(ruby_method_name, ole_method_name = nil)
51
+ ole_method_name = ruby_method_name unless ole_method_name
52
+ class_eval "def #{ruby_method_name}
53
+ assert_exists
54
+ # Every element has its name starting from element. If yes then
55
+ # use element_name to send the command to jssh. Else its a number
56
+ # and we are still searching for element, in this case use doc.all
57
+ # array with element_name as index to send command to jssh
58
+ #puts element_object.to_s
59
+ #if(@element_type == 'HTMLDivElement')
60
+ # ole_method_name = 'innerHTML'
61
+ #end
62
+ jssh_socket.send('typeof(' + element_object + '.#{ole_method_name});\n', 0)
63
+ return_type = read_socket()
64
+
65
+ return_value = get_attribute_value(\"#{ole_method_name}\")
66
+
67
+ #if(return_value == '' || return_value == \"null\")
68
+ # return_value = \"\"
69
+ #end
70
+
71
+ if(return_type == \"boolean\")
72
+ return_value = false if return_value == \"false\"
73
+ return_value = true if return_value == \"true\"
74
+ end
75
+ #puts return_value
76
+ @@current_level = 0
77
+ return return_value
78
+ end"
79
+ end
80
+
81
+ def get_attribute_value(attribute_name)
82
+ #if the attribut name is columnLength get number of cells in first row if rows exist.
83
+ case attribute_name
84
+ when "columnLength"
85
+ rowsLength = js_eval_method "columns"
86
+ if (rowsLength != 0 || rowsLength != "")
87
+ return js_eval_method("rows[0].cells.length")
88
+ end
89
+ when "text"
90
+ return text
91
+ when "url", "href", "src", "action", "name"
92
+ return_value = js_eval_method("getAttribute(\"#{attribute_name}\")")
93
+ else
94
+ jssh_command = "var attribute = '';
95
+ if(#{element_object}.#{attribute_name} != undefined)
96
+ attribute = #{element_object}.#{attribute_name};
97
+ else
98
+ attribute = #{element_object}.getAttribute(\"#{attribute_name}\");
99
+ attribute;"
100
+ return_value = js_eval(jssh_command)
101
+ end
102
+ if attribute_name == "value"
103
+ tagName = js_eval_method("tagName").downcase
104
+ type = js_eval_method("type").downcase
105
+
106
+ if tagName == "button" || ["image", "submit", "reset", "button"].include?(type)
107
+ if return_value == "" || return_value == "null"
108
+ return_value = js_eval_method "innerHTML"
109
+ end
110
+ end
111
+ end
112
+
113
+ if return_value == "null" || return_value =~ /\[object\s.*\]/
114
+ return_value = ""
115
+ end
116
+ return return_value
117
+ end
118
+ private :get_attribute_value
119
+
120
+
121
+ #
122
+ # Description:
123
+ # Returns an array of the properties of an element, in a format to be used by the to_s method.
124
+ # additional attributes are returned based on the supplied atributes hash.
125
+ # name, type, id, value and disabled attributes are common to all the elements.
126
+ # This method is used internally by to_s method.
127
+ #
128
+ # Output:
129
+ # Array with values of the following properties:
130
+ # name, type, id, value disabled and the supplied attribues list.
131
+ #
132
+ def string_creator(attributes = nil)
133
+ n = []
134
+ n << "name:".ljust(TO_S_SIZE) + get_attribute_value("name")
135
+ n << "type:".ljust(TO_S_SIZE) + get_attribute_value("type")
136
+ n << "id:".ljust(TO_S_SIZE) + get_attribute_value("id")
137
+ n << "value:".ljust(TO_S_SIZE) + get_attribute_value("value")
138
+ n << "disabled:".ljust(TO_S_SIZE) + get_attribute_value("disabled")
139
+ #n << "style:".ljust(TO_S_SIZE) + get_attribute_value("style")
140
+ #n << "class:".ljust(TO_S_SIZE) + get_attribute_value("className")
141
+
142
+ if(attributes != nil)
143
+ attributes.each do |key,value|
144
+ n << "#{key}:".ljust(TO_S_SIZE) + get_attribute_value(value)
145
+ end
146
+ end
147
+ return n
148
+ end
149
+
150
+ #
151
+ # Description:
152
+ # Sets and clears the colored highlighting on the currently active element.
153
+ #
154
+ # Input:
155
+ # set_or_clear - this can have following two values
156
+ # :set - To set the color of the element.
157
+ # :clear - To clear the color of the element.
158
+ #
159
+ def highlight(set_or_clear)
160
+ if set_or_clear == :set
161
+ #puts "element_name is : #{element_object}"
162
+ jssh_command = " var original_color = #{element_object}.style.background;"
163
+ jssh_command << " #{element_object}.style.background = \"#{DEFAULT_HIGHLIGHT_COLOR}\"; original_color;"
164
+
165
+ # TODO: Need to change this so that it would work if user sets any other color.
166
+ #puts "color is : #{DEFAULT_HIGHLIGHT_COLOR}"
167
+ jssh_socket.send("#{jssh_command}\n", 0)
168
+ @original_color = read_socket()
169
+
170
+ else # BUG: assumes is :clear, but could actually be anything
171
+ begin
172
+ jssh_socket.send("#{element_object}.style.background = \"#{@original_color}\";\n", 0)
173
+ read_socket()
174
+ rescue
175
+ # we could be here for a number of reasons...
176
+ # e.g. page may have reloaded and the reference is no longer valid
177
+ ensure
178
+ @original_color = nil
179
+ end
180
+ end
181
+ end
182
+ protected :highlight
183
+
184
+ #
185
+ # Description:
186
+ # Returns array of rows for a given table. Returns nil if calling element is not of table type.
187
+ #
188
+ # Output:
189
+ # Array of row elements in an table or nil
190
+ #
191
+ def get_rows()
192
+ #puts "#{element_object} and #{element_type}"
193
+ if(element_type == "HTMLTableElement")
194
+ jssh_socket.send("#{element_object}.rows.length;\n", 0)
195
+ length = read_socket().to_i
196
+ #puts "The number of rows in the table are : #{no_of_rows}"
197
+ return_array = Array.new(length)
198
+ for i in 0..length - 1 do
199
+ return_array[i] = "#{element_object}.rows[#{i}]"
200
+ end
201
+ return return_array
202
+ else
203
+ puts "Trying to access rows for Element of type #{element_type}. Element must be of table type to execute this function."
204
+ return nil
205
+ end
206
+ end
207
+ private :get_rows
208
+
209
+ def set_specifier(how, what)
210
+ if how.class == Hash and what.nil?
211
+ specifiers = how
212
+ else
213
+ specifiers = {how => what}
214
+ end
215
+
216
+ @specifiers = {:index => 1} # default if not specified
217
+
218
+ specifiers.each do |how, what|
219
+ what = what.to_i if how == :index
220
+ how = :href if how == :url
221
+ how = :value if how == :caption
222
+ how = :class if how == :class_name
223
+
224
+ @specifiers[how] = what
225
+ end
226
+ end
227
+
228
+ #
229
+ # Description:
230
+ # Locates the element on the page depending upon the parameters passed. Logic for locating the element is written
231
+ # in JavaScript and then send to JSSh; so that we don't make small round-trips via socket to JSSh. This is done to
232
+ # improve the performance for locating the element.
233
+ #
234
+ # Input:
235
+ # tag - Tag name of the element to be located like "input", "a" etc. This is case insensitive.
236
+ # how - The attribute by which you want to locate the element like id, name etc. You can use any attribute-value pair
237
+ # that uniquely identifies that element on the page. If there are more that one element that have identical
238
+ # attribute-value pair then first element that is found while traversing the DOM will be returned.
239
+ # what - The value of the attribute specified by how.
240
+ # types - Used if that HTML element to be located has different type like input can be of type image, button etc.
241
+ # Default value is nil
242
+ # value - This is used only in case of radio buttons where they have same name but different value.
243
+ #
244
+ # Output:
245
+ # Returns nil if unable to locate the element, else return the element.
246
+ #
247
+ def locate_tagged_element(tag, how, what, types = nil, value = nil)
248
+ #puts caller(0)
249
+ # how = :value if how == :caption
250
+ # how = :href if how == :url
251
+ set_specifier(how, what)
252
+ #puts "(locate_tagged_element)current element is : #{@container.class} and tag is #{tag}"
253
+ # If there is no current element i.e. element in current context we are searching the whole DOM tree.
254
+ # So get all the elements.
255
+
256
+ if(types != nil and types.include?("button"))
257
+ jssh_command = "var isButtonElement = true;"
258
+ else
259
+ jssh_command = "var isButtonElement = false;"
260
+ end
261
+
262
+ # Because in both the below cases we need to get element with respect to document.
263
+ # when we locate a frame document is automatically adjusted to point to HTML inside the frame
264
+ if(@container.class == FireWatir::Firefox || @container.class == Frame)
265
+ #end
266
+ #if(@@current_element_object == "")
267
+ jssh_command << "var elements_#{tag} = null; elements_#{tag} = #{@container.document_var}.getElementsByTagName(\"#{tag}\");"
268
+ if(types != nil and (types.include?("textarea") or types.include?("button")) )
269
+ jssh_command << "elements_#{tag} = #{@container.document_var}.body.getElementsByTagName(\"*\");"
270
+ end
271
+ # @@has_changed = true
272
+ else
273
+ #puts "container name is: " + @container.element_name
274
+ #locate if defined? locate
275
+ #@container.locate
276
+ jssh_command << "var elements_#{@@current_level}_#{tag} = #{@container.element_name}.getElementsByTagName(\"#{tag}\");"
277
+ if(types != nil and (types.include?("textarea") or types.include?("button") ) )
278
+ jssh_command << "elements_#{@@current_level}_#{tag} = #{@container.element_name}.getElementsByTagName(\"*\");"
279
+ end
280
+ # @@has_changed = false
281
+ end
282
+
283
+
284
+ if(types != nil)
285
+ jssh_command << "var types = new Array("
286
+ count = 0
287
+ types.each do |type|
288
+ if count == 0
289
+ jssh_command << "\"#{type}\""
290
+ count += 1
291
+ else
292
+ jssh_command << ",\"#{type}\""
293
+ end
294
+ end
295
+ jssh_command << ");"
296
+ else
297
+ jssh_command << "var types = null;"
298
+ end
299
+ #jssh_command << "var elements = #{element_object}.getElementsByTagName('*');"
300
+ jssh_command << "var object_index = 1; var o = null; var element_name = \"\";"
301
+
302
+ case value
303
+ when Regexp
304
+ jssh_command << "var value = #{ rb_regexp_to_js(value) };"
305
+ when nil
306
+ jssh_command << "var value = null;"
307
+ else
308
+ jssh_command << "var value = \"#{value}\";"
309
+ end
310
+
311
+ #add hash arrays
312
+ sKey = "var hashKeys = new Array("
313
+ sVal = "var hashValues = new Array("
314
+ @specifiers.each do |k,v|
315
+ sKey += "\"#{k}\","
316
+ if v.is_a?(Regexp)
317
+ sVal += "#{rb_regexp_to_js(v)},"
318
+ else
319
+ sVal += "\"#{v}\","
320
+ end
321
+ end
322
+ sKey = sKey[0..sKey.length-2]
323
+ sVal = sVal[0..sVal.length-2]
324
+ jssh_command << sKey + ");"
325
+ jssh_command << sVal + ");"
326
+
327
+ #index
328
+ jssh_command << "var target_index = 1;
329
+ for(var k=0; k<hashKeys.length; k++)
330
+ {
331
+ if(hashKeys[k] == \"index\")
332
+ {
333
+ target_index = parseInt(hashValues[k]);
334
+ break;
335
+ }
336
+ }"
337
+
338
+ #jssh_command << "elements.length;"
339
+ if(@container.class == FireWatir::Firefox || @container.class == Frame)
340
+
341
+ jssh_command << "for(var i=0; i<elements_#{tag}.length; i++)
342
+ {
343
+ if(element_name != \"\") break;
344
+ var element = elements_#{tag}[i];"
345
+ else
346
+ jssh_command << "for(var i=0; i<elements_#{@@current_level}_#{tag}.length; i++)
347
+ {
348
+ if(element_name != \"\") break;
349
+ var element = elements_#{@@current_level}_#{tag}[i];"
350
+ end
351
+
352
+ # Because in IE for button the value of "value" attribute also corresponds to the innerHTML if value attribute
353
+ # is not supplied. For e.g.: <button>Sign In</button>, in this case value of "value" attribute is "Sign In"
354
+ # though value attribute is not supplied. But for Firefox value of "value" attribute is null. So to make sure
355
+ # script runs on both IE and Watir we are also considering innerHTML if element is of button type.
356
+ jssh_command << " var attribute = \"\";
357
+ var same_type = false;
358
+ if(types)
359
+ {
360
+ for(var j=0; j<types.length; j++)
361
+ {
362
+ if(types[j] == element.type || types[j] == element.tagName)
363
+ {
364
+ same_type = true;
365
+ break;
366
+ }
367
+ }
368
+ }
369
+ else
370
+ {
371
+ same_type = true;
372
+ }
373
+ if(same_type == true)
374
+ {
375
+ var how = \"\";
376
+ var what = null;
377
+ attribute = \"\";
378
+ for(var k=0; k<hashKeys.length; k++)
379
+ {
380
+ how = hashKeys[k];
381
+ what = hashValues[k];
382
+
383
+ if(how == \"index\")
384
+ {
385
+ attribute = parseInt(what);
386
+ what = parseInt(what);
387
+ }
388
+ else
389
+ {
390
+ if(how == \"text\")
391
+ {
392
+ attribute = element.textContent.replace(/\\xA0/g,' ').replace(/^\\s+|\\s+$/g, '').replace(/\\s+/g, ' ')
393
+ }
394
+ else
395
+ {
396
+ if(how == \"href\" || how == \"src\" || how == \"action\" || how == \"name\")
397
+ {
398
+ attribute = element.getAttribute(how);
399
+ }
400
+ else
401
+ {
402
+ if(eval(\"element.\"+how) != undefined)
403
+ attribute = eval(\"element.\"+how);
404
+ else
405
+ attribute = element.getAttribute(how);
406
+ }
407
+ }
408
+ if(\"value\" == how && isButtonElement && (attribute == null || attribute == \"\"))
409
+ {
410
+ attribute = element.innerHTML;
411
+ }
412
+ }
413
+ if(attribute == \"\") o = 'NoMethodError';
414
+ var found = false;
415
+ if (typeof what == \"object\" || typeof what == \"function\")
416
+ {
417
+ var regExp = new RegExp(what);
418
+ found = regExp.test(attribute);
419
+ }
420
+ else
421
+ {
422
+ found = (attribute == what);
423
+ }"
424
+
425
+ if(@container.class == FireWatir::Firefox || @container.class == Frame)
426
+ jssh_command << " if(found)
427
+ {
428
+ if(value)
429
+ {
430
+ if(element.value == value || (value.test && value.test(element.value)))
431
+ {
432
+ o = element;
433
+ element_name = \"elements_#{tag}[\" + i + \"]\";
434
+ }
435
+ else
436
+ break;
437
+ }
438
+ else
439
+ {
440
+ o = element;
441
+ element_name = \"elements_#{tag}[\" + i + \"]\";
442
+ }
443
+ }"
444
+ else
445
+ jssh_command << " if(found)
446
+ {
447
+ if(value)
448
+ {
449
+ if(element.value == value || (value.test && value.test(element.value)))
450
+ {
451
+ o = element;
452
+ element_name = \"elements_#{@@current_level}_#{tag}[\" + i + \"]\";
453
+ }
454
+ else
455
+ break;
456
+ }
457
+ else
458
+ {
459
+ o = element;
460
+ element_name = \"elements_#{@@current_level}_#{tag}[\" + i + \"]\";
461
+ }
462
+ }"
463
+ end
464
+
465
+ jssh_command << "
466
+ else {
467
+ o = null;
468
+ element_name = \"\";
469
+ break;
470
+ }
471
+ }
472
+ if(element_name != \"\")
473
+ {
474
+ if(target_index == object_index)
475
+ {
476
+ break;
477
+ }
478
+ else if(target_index < object_index)
479
+ {
480
+ element_name = \"\";
481
+ o = null;
482
+ break;
483
+ }
484
+ else
485
+ {
486
+ object_index += 1;
487
+ element_name = \"\";
488
+ o = null;
489
+ }
490
+ }
491
+ }
492
+ }
493
+ element_name;"
494
+
495
+ # Remove \n that are there in the string as a result of pressing enter while formatting.
496
+ jssh_command.gsub!(/\n/, "")
497
+ #puts jssh_command
498
+ #out = File.new("c:\\result.log", "w")
499
+ #out << jssh_command
500
+ #out.close
501
+ jssh_socket.send("#{jssh_command};\n", 0)
502
+ element_name = read_socket();
503
+ #puts "element name in find control is : #{element_name}"
504
+ @@current_level = @@current_level + 1
505
+ #puts @container
506
+ #puts element_name
507
+ if(element_name != "")
508
+ return element_name #Element.new(element_name, @container)
509
+ else
510
+ return nil
511
+ end
512
+ end
513
+
514
+ def rb_regexp_to_js(regexp)
515
+ old_exp = regexp.to_s
516
+ new_exp = regexp.inspect.sub(/\w*$/, '')
517
+ flags = old_exp.slice(2, old_exp.index(':') - 2)
518
+
519
+ for i in 0..flags.length do
520
+ flag = flags[i, 1]
521
+ if(flag == '-')
522
+ break;
523
+ else
524
+ new_exp << flag
525
+ end
526
+ end
527
+
528
+ new_exp
529
+ end
530
+
531
+ #
532
+ # Description:
533
+ # Locates frame element. Logic for locating the frame is written in JavaScript so that we don't make small
534
+ # round trips to JSSh using socket. This is done to improve the performance for locating the element.
535
+ #
536
+ # Input:
537
+ # how - The attribute for locating the frame. You can use any attribute-value pair that uniquely identifies
538
+ # the frame on the page. If there are more than one frames that have identical attribute-value pair
539
+ # then first frame that is found while traversing the DOM will be returned.
540
+ # what - Value of the attribute specified by how
541
+ #
542
+ # Output:
543
+ # Nil if unable to locate frame, else return the Frame element.
544
+ #
545
+ # TODO/FIX: If multiple tabs are open on the current window, will count frames from every tab, not just the current tab.
546
+ #
547
+ def locate_frame(how, what)
548
+ # Get all the frames the are there on the page.
549
+ #puts "how is #{how} and what is #{what}"
550
+ jssh_command = ""
551
+ if(@container.class == FireWatir::Firefox)
552
+ # In firefox 3 if you write Frame Name then it will not show anything. So we add .toString function to every element.
553
+ jssh_command = "var frameset = #{@container.window_var}.frames;
554
+ var elements_frames = new Array();
555
+ for(var i = 0; i < frameset.length; i++)
556
+ {
557
+ var frames = frameset[i].frames;
558
+ for(var j = 0; j < frames.length; j++)
559
+ {
560
+ frames[j].frameElement.toString = function() { return '[object HTMLFrameElement]'; };
561
+ elements_frames.push(frames[j].frameElement);
562
+
563
+ }
564
+ }"
565
+ else
566
+ jssh_command = "var frames = #{@container.element_name}.contentWindow.frames;
567
+ var elements_frames_#{@@current_level} = new Array();
568
+ for(var i = 0; i < frames.length; i++)
569
+ {
570
+ elements_frames_#{@@current_level}.push(frames[i].frameElement);
571
+ }"
572
+ end
573
+
574
+ jssh_command << " var element_name = ''; var object_index = 1;var attribute = '';
575
+ var element = '';"
576
+ if(@container.class == FireWatir::Firefox)
577
+ jssh_command << "for(var i = 0; i < elements_frames.length; i++)
578
+ {
579
+ element = elements_frames[i];"
580
+ else
581
+ jssh_command << "for(var i = 0; i < elements_frames_#{@@current_level}.length; i++)
582
+ {
583
+ element = elements_frames_#{@@current_level}[i];"
584
+ end
585
+ jssh_command << " if(\"index\" == \"#{how}\")
586
+ {
587
+ attribute = object_index; object_index += 1;
588
+ }
589
+ else
590
+ {
591
+ attribute = element.getAttribute(\"#{how}\");
592
+ if(attribute == \"\" || attribute == null)
593
+ {
594
+ attribute = element.#{how};
595
+ }
596
+ }
597
+ var found = false;"
598
+ if(what.class == Regexp)
599
+ oldRegExp = what.to_s
600
+ newRegExp = "/" + what.source + "/"
601
+ flags = oldRegExp.slice(2, oldRegExp.index(':') - 2)
602
+
603
+ for i in 0..flags.length do
604
+ flag = flags[i, 1]
605
+ if(flag == '-')
606
+ break;
607
+ else
608
+ newRegExp << flag
609
+ end
610
+ end
611
+ #puts "old reg ex is #{what} new reg ex is #{newRegExp}"
612
+ jssh_command << " var regExp = new RegExp(#{newRegExp});
613
+ found = regExp.test(attribute);"
614
+ elsif(how == :index)
615
+ jssh_command << " found = (attribute == #{what});"
616
+ else
617
+ jssh_command << " found = (attribute == \"#{what}\");"
618
+ end
619
+
620
+ jssh_command << " if(found)
621
+ {"
622
+ if(@container.class == FireWatir::Firefox)
623
+ jssh_command << " element_name = \"elements_frames[\" + i + \"]\";
624
+ #{@container.document_var} = elements_frames[i].contentDocument;
625
+ #{@container.body_var} = #{@container.document_var}.body;"
626
+ else
627
+ jssh_command << " element_name = \"elements_frames_#{@@current_level}[\" + i + \"]\";
628
+ #{@container.document_var} = elements_frames_#{@@current_level}[i].contentDocument;
629
+ #{@container.body_var} = #{@container.document_var}.body;"
630
+ end
631
+ jssh_command << " break;
632
+ }
633
+ }
634
+ element_name;"
635
+
636
+ jssh_command.gsub!("\n", "")
637
+ #puts "jssh_command for finding frame is : #{jssh_command}"
638
+
639
+ jssh_socket.send("#{jssh_command};\n", 0)
640
+ element_name = read_socket()
641
+ @@current_level = @@current_level + 1
642
+ #puts "element_name for frame is : #{element_name}"
643
+
644
+ if(element_name != "")
645
+ return element_name
646
+ else
647
+ return nil
648
+ end
649
+ end
650
+
651
+ def get_frame_html
652
+ jssh_socket.send("var htmlelem = #{@container.document_var}.getElementsByTagName('html')[0]; htmlelem.innerHTML;\n", 0)
653
+ #jssh_socket.send("body.innerHTML;\n", 0)
654
+ result = read_socket()
655
+ return "<html>" + result + "</html>"
656
+ end
657
+
658
+ def submit_form
659
+ #puts "form name is : #{element_object}"
660
+ jssh_socket.send("#{element_object}.submit();\n" , 0)
661
+ read_socket()
662
+ end
663
+
664
+ public
665
+
666
+ #
667
+ #
668
+ # Description:
669
+ # Matches the given text with the current text shown in the browser for that particular element.
670
+ #
671
+ # Input:
672
+ # target - Text to match. Can be a string or regex
673
+ #
674
+ # Output:
675
+ # Returns the index if the specified text was found.
676
+ # Returns matchdata object if the specified regexp was found.
677
+ #
678
+ def contains_text(target)
679
+ #puts "Text to match is : #{match_text}"
680
+ #puts "Html is : #{self.text}"
681
+ if target.kind_of? Regexp
682
+ self.text.match(target)
683
+ elsif target.kind_of? String
684
+ self.text.index(target)
685
+ else
686
+ raise TypeError, "Argument #{target} should be a string or regexp."
687
+ end
688
+ end
689
+
690
+
691
+ def inspect
692
+ '#<%s:0x%x located=%s how=%s what=%s>' % [self.class, hash*2, !!@o, @how.inspect, @what.inspect]
693
+ end
694
+
695
+ #
696
+ # Description:
697
+ # Returns array of elements that matches a given XPath query.
698
+ # Mozilla browser directly supports XPath query on its DOM. So no need to create the DOM tree as WATiR does for IE.
699
+ # Refer: http://developer.mozilla.org/en/docs/DOM:document.evaluate
700
+ # Used internally by Firewatir use ff.elements_by_xpath instead.
701
+ #
702
+ # Input:
703
+ # xpath - The xpath expression or query.
704
+ #
705
+ # Output:
706
+ # Array of elements that matched the xpath expression provided as parameter.
707
+ #
708
+ def elements_by_xpath(container, xpath)
709
+ rand_no = rand(1000)
710
+ #jssh_command = "var xpathResult = document.evaluate(\"count(#{xpath})\", document, null, #{NUMBER_TYPE}, null); xpathResult.numberValue;"
711
+ #jssh_socket.send("#{jssh_command}\n", 0);
712
+ #node_count = read_socket()
713
+ xpath.gsub!("\"", "\\\"")
714
+ jssh_command = "var element_xpath_#{rand_no} = new Array();"
715
+
716
+ jssh_command << "var result = #{@container.document_var}.evaluate(\"#{xpath}\", #{@container.document_var}, null, #{ORDERED_NODE_ITERATOR_TYPE}, null);
717
+ var iterate = result.iterateNext();
718
+ while(iterate)
719
+ {
720
+ element_xpath_#{rand_no}.push(iterate);
721
+ iterate = result.iterateNext();
722
+ }
723
+ element_xpath_#{rand_no}.length;
724
+ "
725
+
726
+ # Remove \n that are there in the string as a result of pressing enter while formatting.
727
+ jssh_command.gsub!(/\n/, "")
728
+ #puts jssh_command
729
+ jssh_socket.send("#{jssh_command};\n", 0)
730
+ node_count = read_socket()
731
+ #puts "value of count is : #{node_count}"
732
+
733
+ elements = Array.new(node_count.to_i)
734
+
735
+ for i in 0..elements.length - 1 do
736
+ elements[i] = "element_xpath_#{rand_no}[#{i}]"
737
+ end
738
+
739
+ return elements;
740
+ end
741
+
742
+ #
743
+ # Description:
744
+ # Returns first element found while traversing the DOM; that matches an given XPath query.
745
+ # Mozilla browser directly supports XPath query on its DOM. So no need to create the DOM tree as WATiR does for IE.
746
+ # Refer: http://developer.mozilla.org/en/docs/DOM:document.evaluate
747
+ # Used internally by Firewatir use ff.element_by_xpath instead.
748
+ #
749
+ # Input:
750
+ # xpath - The xpath expression or query.
751
+ #
752
+ # Output:
753
+ # First element in DOM that matched the XPath expression or query.
754
+ #
755
+ def element_by_xpath(container, xpath)
756
+ #puts "here locating element by xpath"
757
+ rand_no = rand(1000)
758
+ xpath.gsub!("\"", "\\\"")
759
+ jssh_command = "var element_xpath_#{rand_no} = null; element_xpath_#{rand_no} = #{@container.document_var}.evaluate(\"#{xpath}\", #{container.document_var}, null, #{FIRST_ORDERED_NODE_TYPE}, null).singleNodeValue; element_xpath_#{rand_no};"
760
+
761
+ jssh_socket.send("#{jssh_command}\n", 0)
762
+ result = read_socket()
763
+ #puts "command send to jssh is : #{jssh_command}"
764
+ #puts "result is : #{result}"
765
+ if(result == "null" || result == "" || result.include?("exception"))
766
+ @@current_level = 0
767
+ return nil
768
+ else
769
+ @@current_level += 1
770
+ return "element_xpath_#{rand_no}"
771
+ end
772
+ end
773
+
774
+ #
775
+ # Description:
776
+ # Returns the name of the element with which we can access it in JSSh.
777
+ # Used internally by Firewatir to execute methods, set properties or return property value for the element.
778
+ #
779
+ # Output:
780
+ # Name of the variable with which element is referenced in JSSh
781
+ #
782
+ def element_object
783
+ #puts caller.join("\n")
784
+ #puts "In element_object element name is : #{@element_name}"
785
+ #puts "in element_object : #{@container.class}"
786
+ #if(@container.class == FireWatir::Firefox)
787
+ return @element_name #if @element_name != nil
788
+ #else
789
+ # return @container.element_name
790
+ #end
791
+ #return @o.element_name if @o != nil
792
+ end
793
+ private :element_object
794
+
795
+ #
796
+ # Description:
797
+ # Returns the type of element. For e.g.: HTMLAnchorElement. used internally by Firewatir
798
+ #
799
+ # Output:
800
+ # Type of the element.
801
+ #
802
+ def element_type
803
+ #puts "in element_type object is : #{element_object}"
804
+ # Get the type of the element.
805
+ jssh_socket.send("#{element_object};\n", 0)
806
+ temp = read_socket()
807
+
808
+ #puts "#{element_object} and type is #{temp}"
809
+ temp =~ /\[object\s(.*)\]/
810
+ if $1
811
+ return $1
812
+ else
813
+ # This is done because in JSSh if you write element name of anchor type
814
+ # then it displays the link to which it navigates instead of displaying
815
+ # object type. So above regex match will return nil
816
+ return "HTMLAnchorElement"
817
+ end
818
+ end
819
+ #private :element_type
820
+
821
+ #
822
+ # Description:
823
+ # Fires the provided event for an element and by default waits for the action to get completed.
824
+ #
825
+ # Input:
826
+ # event - Event to be fired like "onclick", "onchange" etc.
827
+ # wait - Whether to wait for the action to get completed or not. By default its true.
828
+ #
829
+ # TODO: Provide ability to specify event parameters like keycode for key events, and click screen
830
+ # coordinates for mouse events.
831
+ def fire_event(event, wait = true)
832
+ assert_exists()
833
+ event = event.to_s # in case event was given as a symbol
834
+
835
+ event = event.downcase
836
+
837
+ event =~ /on(.*)/i
838
+ event = $1 if $1
839
+
840
+ # check if we've got an old-school on-event
841
+ #jssh_socket.send("typeof(#{element_object}.#{event});\n", 0)
842
+ #is_defined = read_socket()
843
+
844
+ # info about event types harvested from:
845
+ # http://www.howtocreate.co.uk/tutorials/javascript/domevents
846
+ case event
847
+ when 'abort', 'blur', 'change', 'error', 'focus', 'load', 'reset', 'resize',
848
+ 'scroll', 'select', 'submit', 'unload'
849
+ dom_event_type = 'HTMLEvents'
850
+ dom_event_init = "initEvent(\"#{event}\", true, true)"
851
+ when 'keydown', 'keypress', 'keyup'
852
+ dom_event_type = 'KeyEvents'
853
+ # Firefox has a proprietary initializer for keydown/keypress/keyup.
854
+ # Args are as follows:
855
+ # 'type', bubbles, cancelable, windowObject, ctrlKey, altKey, shiftKey, metaKey, keyCode, charCode
856
+ dom_event_init = "initKeyEvent(\"#{event}\", true, true, #{@container.window_var}, false, false, false, false, 0, 0)"
857
+ when 'click', 'dblclick', 'mousedown', 'mousemove', 'mouseout', 'mouseover',
858
+ 'mouseup'
859
+ dom_event_type = 'MouseEvents'
860
+ # Args are as follows:
861
+ # 'type', bubbles, cancelable, windowObject, detail, screenX, screenY, clientX, clientY, ctrlKey, altKey, shiftKey, metaKey, button, relatedTarget
862
+ dom_event_init = "initMouseEvent(\"#{event}\", true, true, #{@container.window_var}, 1, 0, 0, 0, 0, false, false, false, false, 0, null)"
863
+ else
864
+ dom_event_type = 'HTMLEvents'
865
+ dom_event_init = "initEvents(\"#{event}\", true, true)"
866
+ end
867
+
868
+ if(element_type == "HTMLSelectElement")
869
+ dom_event_type = 'HTMLEvents'
870
+ dom_event_init = "initEvent(\"#{event}\", true, true)"
871
+ end
872
+
873
+
874
+ jssh_command = "var event = #{@container.document_var}.createEvent(\"#{dom_event_type}\"); "
875
+ jssh_command << "event.#{dom_event_init}; "
876
+ jssh_command << "#{element_object}.dispatchEvent(event);"
877
+
878
+ #puts "JSSH COMMAND:\n#{jssh_command}\n"
879
+
880
+ jssh_socket.send("#{jssh_command}\n", 0)
881
+ read_socket() if wait
882
+ wait() if wait
883
+
884
+ @@current_level = 0
885
+ end
886
+ alias fireEvent fire_event
887
+
888
+ #
889
+ # Description:
890
+ # Returns the value of the specified attribute of an element.
891
+ #
892
+ def attribute_value(attribute_name)
893
+ #puts attribute_name
894
+ assert_exists()
895
+ return_value = get_attribute_value(attribute_name)
896
+ @@current_level = 0
897
+ return return_value
898
+ end
899
+
900
+ #
901
+ # Description:
902
+ # Checks if element exists or not. Raises UnknownObjectException if element doesn't exists.
903
+ #
904
+ def assert_exists
905
+ unless exists?
906
+ raise UnknownObjectException.new(
907
+ Watir::Exception.message_for_unable_to_locate(@how, @what))
908
+ end
909
+ end
910
+
911
+ #
912
+ # Description:
913
+ # Checks if element is enabled or not. Raises ObjectDisabledException if object is disabled and
914
+ # you are trying to use the object.
915
+ #
916
+ def assert_enabled
917
+ unless enabled?
918
+ raise ObjectDisabledException, "object #{@how} and #{@what} is disabled"
919
+ end
920
+ end
921
+
922
+ #
923
+ # Description:
924
+ # First checks if element exists or not. Then checks if element is enabled or not.
925
+ #
926
+ # Output:
927
+ # Returns true if element exists and is enabled, else returns false.
928
+ #
929
+ def enabled?
930
+ assert_exists
931
+ value = js_eval_method "disabled"
932
+ @@current_level = 0
933
+ return true if(value == "false")
934
+ return false if(value == "true")
935
+ return value
936
+ end
937
+
938
+ #
939
+ # Description:
940
+ # Checks element for display: none or visibility: hidden, these are
941
+ # the most common methods to hide an html element
942
+
943
+ def visible?
944
+ assert_exists
945
+ val = js_eval "var val = 'true'; var str = ''; var obj = #{element_object}; while (obj != null) { try { str = #{@container.document_var}.defaultView.getComputedStyle(obj,null).visibility; if (str=='hidden') { val = 'false'; break; } str = #{@container.document_var}.defaultView.getComputedStyle(obj,null).display; if (str=='none') { val = 'false'; break; } } catch(err) {} obj = obj.parentNode; } val;"
946
+ return (val == 'false')? false: true
947
+ end
948
+
949
+
950
+ #
951
+ # Description:
952
+ # Checks if element exists or not. If element is not located yet then first locates the element.
953
+ #
954
+ # Output:
955
+ # True if element exists, false otherwise.
956
+ #
957
+ def exists?
958
+ # puts "element is : #{element_object}"
959
+ # puts caller(0)
960
+ # If elements array has changed locate the element again. So that the element name points to correct element.
961
+ if(element_object == nil || element_object == "")
962
+ @@current_level = 0
963
+ #puts "locating element"
964
+ locate if respond_to?(:locate)
965
+ if(@element_name == nil || @element_name == "")
966
+ return false
967
+ else
968
+ #puts caller(0)
969
+ #puts "element name is : #{@element_name}"
970
+ return true
971
+ end
972
+ else
973
+ #puts "not locating the element again"
974
+ return true
975
+ end
976
+ #@@current_level = 0
977
+ #if(element_object == nil || element_object == "")
978
+ # return false
979
+ #else
980
+ # return true
981
+ #end
982
+ rescue UnknownFrameException
983
+ false
984
+ end
985
+ alias exist? exists?
986
+
987
+ #
988
+ # Description:
989
+ # Returns the text of the element.
990
+ #
991
+ # Output:
992
+ # Text of the element.
993
+ #
994
+ def text()
995
+ assert_exists
996
+ element = (element_type == "HTMLFrameElement") ? "body" : element_object
997
+ return_value = js_eval("#{element}.textContent.replace(/\\xA0/g, ' ').replace(/\\s+/g, ' ')").strip
998
+ @@current_level = 0
999
+ return return_value
1000
+ end
1001
+ alias innerText text
1002
+
1003
+ # Returns the name of the element (as defined in html)
1004
+ def_wrap :name
1005
+ # Returns the id of the element
1006
+ def_wrap :id
1007
+ # Returns whether the element is disabled
1008
+ def disabled
1009
+ ! enabled?
1010
+ end
1011
+ alias disabled? disabled
1012
+ # Returns the state of the element
1013
+ def_wrap :checked
1014
+ # Returns the value of the element
1015
+ def_wrap :value
1016
+ # Returns the title of the element
1017
+ def_wrap :title
1018
+ # Returns the value of 'alt' attribute in case of Image element.
1019
+ def_wrap :alt
1020
+ # Returns the value of 'href' attribute in case of Anchor element.
1021
+ def_wrap :src
1022
+ # Returns the type of the element. Use in case of Input element only.
1023
+ def_wrap :type
1024
+ # Returns the url the Anchor element points to.
1025
+ def_wrap :href
1026
+ # Return the ID of the control that this label is associated with
1027
+ def_wrap :for, :htmlFor
1028
+ # Returns the class name of the element
1029
+ def_wrap :class_name, :className
1030
+ # Return the html of the object
1031
+ def_wrap :html, :innerHTML
1032
+ # Return the action of form
1033
+ def_wrap :action
1034
+
1035
+ #
1036
+ # Description:
1037
+ # Display basic details about the object. Sample output for a button is shown.
1038
+ # Raises UnknownObjectException if the object is not found.
1039
+ # name b4
1040
+ # type button
1041
+ # id b5
1042
+ # value Disabled Button
1043
+ # disabled true
1044
+ #
1045
+ # Output:
1046
+ # Array with value of properties shown above.
1047
+ #
1048
+ def to_s(attributes=nil)
1049
+ #puts "here in to_s"
1050
+ #puts caller(0)
1051
+ assert_exists
1052
+ if(element_type == "HTMLTableCellElement")
1053
+ return text()
1054
+ else
1055
+ result = string_creator(attributes).join("\n")
1056
+ @@current_level = 0
1057
+ return result
1058
+ end
1059
+ end
1060
+
1061
+ #
1062
+ # Description:
1063
+ # Function to fire click event on elements.
1064
+ #
1065
+ def click
1066
+ assert_exists
1067
+ assert_enabled
1068
+
1069
+ highlight(:set)
1070
+ #puts "#{element_object} and #{element_type}"
1071
+ case element_type
1072
+
1073
+ when "HTMLAnchorElement", "HTMLImageElement"
1074
+ # Special check for link or anchor tag. Because click() doesn't work on links.
1075
+ # More info: http://www.w3.org/TR/DOM-Level-2-HTML/html.html#ID-48250443
1076
+ # https://bugzilla.mozilla.org/show_bug.cgi?id=148585
1077
+
1078
+ jssh_command = "var event = #{@container.document_var}.createEvent(\"MouseEvents\");"
1079
+
1080
+ # Info about initMouseEvent at: http://www.xulplanet.com/references/objref/MouseEvent.html
1081
+ jssh_command << "event.initMouseEvent('click',true,true,null,1,0,0,0,0,false,false,false,false,0,null);"
1082
+ jssh_command << "#{element_object}.dispatchEvent(event);\n"
1083
+
1084
+ #puts "jssh_command is: #{jssh_command}"
1085
+ jssh_socket.send("#{jssh_command}", 0)
1086
+ read_socket()
1087
+ else
1088
+ jssh_socket.send("typeof(#{element_object}.click);\n", 0)
1089
+ isDefined = read_socket()
1090
+ if(isDefined == "undefined")
1091
+ fire_event("onclick")
1092
+ else
1093
+ jssh_socket.send("#{element_object}.click();\n" , 0)
1094
+ read_socket()
1095
+ end
1096
+ end
1097
+ highlight(:clear)
1098
+ # Wait for firefox to reload.
1099
+ wait()
1100
+ end
1101
+
1102
+ #
1103
+ # Description:
1104
+ # Document var. Unfinished.
1105
+ #
1106
+ def document_var
1107
+ "document"
1108
+ end
1109
+
1110
+ #
1111
+ # Description:
1112
+ # Wait for the browser to get loaded, after the event is being fired.
1113
+ #
1114
+ def wait
1115
+ #ff = FireWatir::Firefox.new
1116
+ #ff.wait()
1117
+ #puts @container
1118
+ @container.wait()
1119
+ @@current_level = 0
1120
+ end
1121
+
1122
+ #
1123
+ # Description:
1124
+ # Function is used for click events that generates javascript pop up.
1125
+ # Doesn't fire the click event immediately instead, it stores the state of the object. User then tells which button
1126
+ # is to be clicked in case a javascript pop up comes after clicking the element. Depending upon the button to be clicked
1127
+ # the functions 'alert' and 'confirm' are re-defined in JavaScript to return appropriate values either true or false. Then the
1128
+ # re-defined functions are send to jssh which then fires the click event of the element using the state
1129
+ # stored above. So the click event is fired in the second statement. Therefore, if you are using this function you
1130
+ # need to call 'click_js_popup_button()' function in the next statement to actually trigger the click event.
1131
+ #
1132
+ # Typical Usage:
1133
+ # ff.button(:id, "button").click_no_wait()
1134
+ # ff.click_js_popup_button("OK")
1135
+ #
1136
+ #def click_no_wait
1137
+ # assert_exists
1138
+ # assert_enabled
1139
+ #
1140
+ # highlight(:set)
1141
+ # @@current_js_object = Element.new("#{element_object}", @container)
1142
+ #end
1143
+
1144
+ #
1145
+ # Description:
1146
+ # Function to click specified button on the javascript pop up. Currently you can only click
1147
+ # either OK or Cancel button.
1148
+ # Functions alert and confirm are redefined so that it doesn't causes the JSSH to get blocked. Also this
1149
+ # will make Firewatir cross platform.
1150
+ #
1151
+ # Input:
1152
+ # button to be clicked
1153
+ #
1154
+ #def click_js_popup(button = "OK")
1155
+ # jssh_command = "var win = browser.contentWindow;"
1156
+ # if(button =~ /ok/i)
1157
+ # jssh_command << "var popuptext = '';win.alert = function(param) {popuptext = param; return true; };
1158
+ # win.confirm = function(param) {popuptext = param; return true; };"
1159
+ # elsif(button =~ /cancel/i)
1160
+ # jssh_command << "var popuptext = '';win.alert = function(param) {popuptext = param; return false; };
1161
+ # win.confirm = function(param) {popuptext = param; return false; };"
1162
+ # end
1163
+ # jssh_command.gsub!(/\n/, "")
1164
+ # jssh_socket.send("#{jssh_command}\n", 0)
1165
+ # read_socket()
1166
+ # click_js_popup_creator_button()
1167
+ # #jssh_socket.send("popuptext_alert;\n", 0)
1168
+ # #read_socket()
1169
+ # jssh_socket.send("\n", 0)
1170
+ # read_socket()
1171
+ #end
1172
+
1173
+ #
1174
+ # Description:
1175
+ # Clicks on button or link or any element that triggers a javascript pop up.
1176
+ # Used internally by function click_js_popup.
1177
+ #
1178
+ #def click_js_popup_creator_button
1179
+ # #puts @@current_js_object.element_name
1180
+ # jssh_socket.send("#{@@current_js_object.element_name}\n;", 0)
1181
+ # temp = read_socket()
1182
+ # temp =~ /\[object\s(.*)\]/
1183
+ # if $1
1184
+ # type = $1
1185
+ # else
1186
+ # # This is done because in JSSh if you write element name of anchor type
1187
+ # # then it displays the link to which it navigates instead of displaying
1188
+ # # object type. So above regex match will return nil
1189
+ # type = "HTMLAnchorElement"
1190
+ # end
1191
+ # #puts type
1192
+ # case type
1193
+ # when "HTMLAnchorElement", "HTMLImageElement"
1194
+ # jssh_command = "var event = document.createEvent(\"MouseEvents\");"
1195
+ # # Info about initMouseEvent at: http://www.xulplanet.com/references/objref/MouseEvent.html
1196
+ # jssh_command << "event.initMouseEvent('click',true,true,null,1,0,0,0,0,false,false,false,false,0,null);"
1197
+ # jssh_command << "#{@@current_js_object.element_name}.dispatchEvent(event);\n"
1198
+ #
1199
+ # jssh_socket.send("#{jssh_command}", 0)
1200
+ # read_socket()
1201
+ # when "HTMLDivElement", "HTMLSpanElement"
1202
+ # jssh_socket.send("typeof(#{element_object}.#{event.downcase});\n", 0)
1203
+ # isDefined = read_socket()
1204
+ # #puts "is method there : #{isDefined}"
1205
+ # if(isDefined != "undefined")
1206
+ # if(element_type == "HTMLSelectElement")
1207
+ # jssh_command = "var event = document.createEvent(\"HTMLEvents\");
1208
+ # event.initEvent(\"click\", true, true);
1209
+ # #{element_object}.dispatchEvent(event);"
1210
+ # jssh_command.gsub!(/\n/, "")
1211
+ # jssh_socket.send("#{jssh_command}\n", 0)
1212
+ # read_socket()
1213
+ # else
1214
+ # jssh_socket.send("#{element_object}.#{event.downcase}();\n", 0)
1215
+ # read_socket()
1216
+ # end
1217
+ # end
1218
+ # else
1219
+ # jssh_command = "#{@@current_js_object.element_name}.click();\n";
1220
+ # jssh_socket.send("#{jssh_command}", 0)
1221
+ # read_socket()
1222
+ # end
1223
+ # @@current_level = 0
1224
+ # @@current_js_object = nil
1225
+ #end
1226
+ #private :click_js_popup_creator_button
1227
+
1228
+ #
1229
+ # Description:
1230
+ # Gets all the cells of the row of a table.
1231
+ #
1232
+ # Output:
1233
+ # Array of table cell elements.
1234
+ #
1235
+ def get_cells
1236
+ assert_exists
1237
+ #puts "element name in cells is : #{element_object}"
1238
+ if(element_type == "HTMLTableRowElement")
1239
+ jssh_socket.send("#{element_object}.cells.length;\n", 0)
1240
+ length = read_socket.to_i
1241
+ return_array = Array.new(length)
1242
+ for i in 0..length - 1 do
1243
+ return_array[i] = "#{element_object}.cells[#{i}]"
1244
+ end
1245
+ return return_array
1246
+ else
1247
+ puts "The element must be of table row type to execute this function."
1248
+ return nil
1249
+ end
1250
+ end
1251
+ private :get_cells
1252
+
1253
+ #
1254
+ # Description:
1255
+ # Traps all the function calls for an element that is not defined and fires them again
1256
+ # as it is to the jssh. This can be used in case the element supports properties or methods
1257
+ # that are not defined in the corresponding element class or in the base class(Element).
1258
+ #
1259
+ # Input:
1260
+ # methodId - Id of the method that is called.
1261
+ # *args - arguments sent to the methods.
1262
+ #
1263
+ def method_missing(methId, *args)
1264
+ methodName = methId.id2name
1265
+ #puts "method name is : #{methodName}"
1266
+ assert_exists
1267
+ #assert_enabled
1268
+ methodName = "colSpan" if methodName == "colspan"
1269
+ if(methodName =~ /invoke/)
1270
+ jssh_command = "#{element_object}."
1271
+ for i in args do
1272
+ jssh_command << i;
1273
+ end
1274
+ #puts "#{jssh_command}"
1275
+ jssh_socket.send("#{jssh_command};\n", 0)
1276
+ return_value = read_socket()
1277
+ #puts "return value is : #{return_value}"
1278
+ return return_value
1279
+ else
1280
+ #assert_exists
1281
+ #puts "element name is #{element_object}"
1282
+
1283
+ # We get method name with trailing '=' when we try to assign a value to a
1284
+ # property. So just remove the '=' to get the type
1285
+ temp = ""
1286
+ assigning_value = false
1287
+ if(methodName =~ /(.*)=$/)
1288
+ temp = "#{element_object}.#{$1}"
1289
+ assigning_value = true
1290
+ else
1291
+ temp = "#{element_object}.#{methodName}"
1292
+ end
1293
+ #puts "temp is : #{temp}"
1294
+
1295
+ jssh_socket.send("typeof(#{temp});\n", 0)
1296
+ method_type = read_socket()
1297
+ #puts "method_type is : #{method_type}"
1298
+
1299
+ if(assigning_value)
1300
+ if(method_type != "boolean" && args[0].class != Fixnum)
1301
+ args[0].gsub!("\\", "\\"*4)
1302
+ args[0].gsub!("\"", "\\\"")
1303
+ args[0].gsub!("\n","\\n")
1304
+ jssh_command = "#{element_object}.#{methodName}\"#{args[0]}\""
1305
+ else
1306
+ jssh_command = "#{element_object}.#{methodName}#{args[0]}"
1307
+ end
1308
+ #puts "jssh_command is : #{jssh_command}"
1309
+ jssh_socket.send("#{jssh_command};\n", 0)
1310
+ read_socket()
1311
+ return
1312
+ end
1313
+
1314
+ methodName = "#{element_object}.#{methodName}"
1315
+ if(args.length == 0)
1316
+ #puts "In if loop #{methodName}"
1317
+ if(method_type == "function")
1318
+ jssh_command = "#{methodName}();\n"
1319
+ else
1320
+ jssh_command = "#{methodName};\n"
1321
+ end
1322
+ else
1323
+ #puts "In else loop : #{methodName}"
1324
+ jssh_command = "#{methodName}("
1325
+
1326
+ count = 0
1327
+ if args != nil
1328
+ for i in args
1329
+ jssh_command << "," if count != 0
1330
+ if i.kind_of? Numeric
1331
+ jssh_command << i.to_s
1332
+ else
1333
+ jssh_command << "\"#{i.to_s.gsub(/"/,"\\\"")}\""
1334
+ end
1335
+ count = count + 1
1336
+ end
1337
+ end
1338
+
1339
+ jssh_command << ");\n"
1340
+ end
1341
+
1342
+ if(method_type == "boolean")
1343
+ jssh_command = jssh_command.gsub("\"false\"", "false")
1344
+ jssh_command = jssh_command.gsub("\"true\"", "true")
1345
+ end
1346
+ #puts "jssh_command is #{jssh_command}"
1347
+ jssh_socket.send("#{jssh_command}", 0)
1348
+ returnValue = read_socket()
1349
+ #puts "return value is : #{returnValue}"
1350
+
1351
+ @@current_level = 0
1352
+
1353
+ if(method_type == "boolean")
1354
+ return false if(returnValue == "false")
1355
+ return true if(returnValue == "true")
1356
+ elsif(method_type == "number")
1357
+ return returnValue.to_i
1358
+ else
1359
+ return returnValue
1360
+ end
1361
+ end
1362
+ end
1363
+
1364
+ end # Element
1365
+ end # FireWatir