firewatir 1.6.2 → 1.6.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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