soda 0.0.1
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.
- data/lib/FieldUtils.rb +102 -0
- data/lib/Soda.rb +2628 -0
- data/lib/SodaCSV.rb +88 -0
- data/lib/SodaFireFox.rb +118 -0
- data/lib/SodaLogReporter.rb +810 -0
- data/lib/SodaReportSummery.rb +470 -0
- data/lib/SodaReporter.rb +452 -0
- data/lib/SodaTestCheck.rb +347 -0
- data/lib/SodaUtils.rb +931 -0
- data/lib/SodaXML.rb +129 -0
- data/lib/fields/CheckBoxField.rb +87 -0
- data/lib/fields/FileField.rb +37 -0
- data/lib/fields/LiField.rb +40 -0
- data/lib/fields/RadioField.rb +44 -0
- data/lib/fields/SelectField.rb +59 -0
- data/lib/fields/SodaField.rb +363 -0
- data/lib/fields/TextField.rb +31 -0
- data/lib/soda.rb +2 -0
- data/lib/utils/sodalookups.rb +465 -0
- metadata +114 -0
data/lib/FieldUtils.rb
ADDED
@@ -0,0 +1,102 @@
|
|
1
|
+
###############################################################################
|
2
|
+
# Copyright (c) 2010, SugarCRM, Inc.
|
3
|
+
# All rights reserved.
|
4
|
+
#
|
5
|
+
# Redistribution and use in source and binary forms, with or without
|
6
|
+
# modification, are permitted provided that the following conditions are met:
|
7
|
+
# * Redistributions of source code must retain the above copyright
|
8
|
+
# notice, this list of conditions and the following disclaimer.
|
9
|
+
# * Redistributions in binary form must reproduce the above copyright
|
10
|
+
# notice, this list of conditions and the following disclaimer in the
|
11
|
+
# documentation and/or other materials provided with the distribution.
|
12
|
+
# * Neither the name of SugarCRM, Inc. nor the
|
13
|
+
# names of its contributors may be used to endorse or promote products
|
14
|
+
# derived from this software without specific prior written permission.
|
15
|
+
#
|
16
|
+
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
17
|
+
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
18
|
+
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
19
|
+
# ARE DISCLAIMED. IN NO EVENT SHALL SugarCRM, Inc. BE LIABLE FOR ANY
|
20
|
+
# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
21
|
+
# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
22
|
+
# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
23
|
+
# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
24
|
+
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
25
|
+
# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
26
|
+
###############################################################################
|
27
|
+
|
28
|
+
###############################################################################
|
29
|
+
# FieldUtils -- Module
|
30
|
+
# This is a module that is for things that only have to deal with
|
31
|
+
# SodaFields.
|
32
|
+
###############################################################################
|
33
|
+
module FieldUtils
|
34
|
+
|
35
|
+
###############################################################################
|
36
|
+
# WatirFieldToStr -- function
|
37
|
+
# This function creates a simple string from the inspect info for a
|
38
|
+
# watir element.
|
39
|
+
#
|
40
|
+
# Input:
|
41
|
+
# field: A watir element object.
|
42
|
+
# reporter: A SodaReporter object.
|
43
|
+
#
|
44
|
+
# Output:
|
45
|
+
# returns a string with inspect info in it, on nil on error.
|
46
|
+
#
|
47
|
+
###############################################################################
|
48
|
+
def FieldUtils.WatirFieldToStr(field, reporter)
|
49
|
+
info = nil
|
50
|
+
msg = ""
|
51
|
+
elm_type = nil
|
52
|
+
|
53
|
+
begin
|
54
|
+
info = field.inspect()
|
55
|
+
info = info.chomp()
|
56
|
+
info =~ /#\<\w+::(\w+):/
|
57
|
+
elm_type = "#{$1}"
|
58
|
+
msg << "#{elm_type}:"
|
59
|
+
info =~ /how=(\{.*\})/i
|
60
|
+
msg << " #{$1}"
|
61
|
+
rescue Exception => e
|
62
|
+
reporter.ReportException(e, true)
|
63
|
+
msg = nil
|
64
|
+
ensure
|
65
|
+
end
|
66
|
+
|
67
|
+
return msg
|
68
|
+
end
|
69
|
+
|
70
|
+
###############################################################################
|
71
|
+
# CheckDisabled -- function
|
72
|
+
# This function checks that a given elements disabled status matches the
|
73
|
+
# expected status, and reports on the findings.
|
74
|
+
#
|
75
|
+
# Input:
|
76
|
+
# field: this is the watir element object to check the status of.
|
77
|
+
# expected: bool, this is the status that is expected.
|
78
|
+
# reporter: A SodaReporter object.
|
79
|
+
#
|
80
|
+
# Output:
|
81
|
+
# Always returns 0.
|
82
|
+
#
|
83
|
+
###############################################################################
|
84
|
+
def FieldUtils.CheckDisabled(field, expected, reporter)
|
85
|
+
element_status = field.disabled()
|
86
|
+
tmp = FieldUtils.WatirFieldToStr(field, reporter)
|
87
|
+
|
88
|
+
if (element_status != expected)
|
89
|
+
msg = "Expected element: #{tmp} state to be disabled = "+
|
90
|
+
"'#{expected}'"+
|
91
|
+
", but found element to be disabled = '#{element_status}'!\n"
|
92
|
+
reporter.ReportFailure(msg)
|
93
|
+
else
|
94
|
+
msg = "Element: #{tmp} state is disabled = '#{element_status}' as "+
|
95
|
+
"expected.\n"
|
96
|
+
reporter.log(msg)
|
97
|
+
end
|
98
|
+
|
99
|
+
return 0
|
100
|
+
end
|
101
|
+
|
102
|
+
end
|
data/lib/Soda.rb
ADDED
@@ -0,0 +1,2628 @@
|
|
1
|
+
###############################################################################
|
2
|
+
# Copyright (c) 2010, SugarCRM, Inc.
|
3
|
+
# All rights reserved.
|
4
|
+
#
|
5
|
+
# Redistribution and use in source and binary forms, with or without
|
6
|
+
# modification, are permitted provided that the following conditions are met:
|
7
|
+
# * Redistributions of source code must retain the above copyright
|
8
|
+
# notice, this list of conditions and the following disclaimer.
|
9
|
+
# * Redistributions in binary form must reproduce the above copyright
|
10
|
+
# notice, this list of conditions and the following disclaimer in the
|
11
|
+
# documentation and/or other materials provided with the distribution.
|
12
|
+
# * Neither the name of SugarCRM, Inc. nor the
|
13
|
+
# names of its contributors may be used to endorse or promote products
|
14
|
+
# derived from this software without specific prior written permission.
|
15
|
+
#
|
16
|
+
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
17
|
+
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
18
|
+
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
19
|
+
# ARE DISCLAIMED. IN NO EVENT SHALL SugarCRM, Inc. BE LIABLE FOR ANY
|
20
|
+
# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
21
|
+
# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
22
|
+
# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
23
|
+
# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
24
|
+
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
25
|
+
# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
26
|
+
###############################################################################
|
27
|
+
|
28
|
+
module Soda
|
29
|
+
|
30
|
+
###############################################################################
|
31
|
+
# Module Global Info:
|
32
|
+
###############################################################################
|
33
|
+
SODA_VERSION = 1.1
|
34
|
+
SODA_WATIR_VERSION = "1.6.7"
|
35
|
+
|
36
|
+
###############################################################################
|
37
|
+
# Needed Ruby libs:
|
38
|
+
###############################################################################
|
39
|
+
require 'rubygems'
|
40
|
+
require 'rbconfig'
|
41
|
+
require 'pathname'
|
42
|
+
require "watir"
|
43
|
+
require 'SodaUtils'
|
44
|
+
require "SodaReporter"
|
45
|
+
require "SodaCSV"
|
46
|
+
require "SodaXML"
|
47
|
+
require 'SodaFireFox'
|
48
|
+
require 'SodaTestCheck'
|
49
|
+
require "utils/sodalookups"
|
50
|
+
require "fields/SodaField"
|
51
|
+
require "fields/TextField"
|
52
|
+
require "fields/CheckBoxField"
|
53
|
+
require "fields/SelectField"
|
54
|
+
require "fields/RadioField"
|
55
|
+
require "fields/FileField"
|
56
|
+
require "fields/LiField"
|
57
|
+
require 'thread'
|
58
|
+
require 'date'
|
59
|
+
|
60
|
+
###############################################################################
|
61
|
+
# Soda -- Class
|
62
|
+
# This class that converts Soda Meta Data into Ruby Watir Commands and
|
63
|
+
# executes them.
|
64
|
+
#
|
65
|
+
# Params:
|
66
|
+
# browser: For setting the default browser. IE/FireFox/...
|
67
|
+
# sugarflavor: This is the type of sugar flavor we are testing: ent,pro...
|
68
|
+
# savehtml: Setting this saves off failed html pages o disk.
|
69
|
+
# hijacks: This is a hash of keys to overwrite csv file values.
|
70
|
+
#
|
71
|
+
###############################################################################
|
72
|
+
class Soda
|
73
|
+
attr_accessor :rep, :browser
|
74
|
+
|
75
|
+
def initialize(params)
|
76
|
+
$curSoda = self;
|
77
|
+
@params = nil
|
78
|
+
@debug = params['debug']
|
79
|
+
@browser = nil
|
80
|
+
@saveHtml = params['savehtml']
|
81
|
+
@blocked_files = []
|
82
|
+
@fileStack = [] # used for keeping track of which file we are in #
|
83
|
+
@curEl = nil # current element being used #
|
84
|
+
$link_not_assert = false
|
85
|
+
$skip_css_errors = false
|
86
|
+
@newCSV = []
|
87
|
+
$SodaHome = Dir.getwd()
|
88
|
+
@current_os = SodaUtils.GetOsType()
|
89
|
+
@sugarFlavor = params['flavor'] if (params.key?('flavor'))
|
90
|
+
@resultsDir = params['resultsdir'] if (params.key?('resultsdir'))
|
91
|
+
@globalVars = params['gvars'] if (params.key?('gvars'))
|
92
|
+
@SIGNAL_STOP = false
|
93
|
+
@hiJacks = nil
|
94
|
+
@breakExit = false
|
95
|
+
@currentTestFile = ""
|
96
|
+
@exceptionExit = false
|
97
|
+
@ieHwnd = 0
|
98
|
+
$global_time = Time.now()
|
99
|
+
$mutex = Mutex.new()
|
100
|
+
@whiteList = []
|
101
|
+
@white_list_file = ""
|
102
|
+
@restart_test = ""
|
103
|
+
@restart_count = 0
|
104
|
+
@non_lib_test_count = 0
|
105
|
+
@last_test = ""
|
106
|
+
@SugarWait = false
|
107
|
+
@restart_test_running = false
|
108
|
+
@FAILEDTESTS = []
|
109
|
+
@vars = Hash.new
|
110
|
+
blocked_file_list = "scripts/sugarcrm/modules/blockScriptList.xml"
|
111
|
+
whitelist_file = "scripts/sugarcrm/modules/whitelist.xml"
|
112
|
+
result = nil
|
113
|
+
sigs = [
|
114
|
+
"INT",
|
115
|
+
"ABRT",
|
116
|
+
"KILL"
|
117
|
+
]
|
118
|
+
err = 0
|
119
|
+
|
120
|
+
if (@globalVars.key?('scriptsdir'))
|
121
|
+
blocked_file_list = "#{@globalVars['scriptsdir']}/modules/" +
|
122
|
+
"blockScriptList.xml"
|
123
|
+
whitelist_file = "#{@globalVars['scriptsdir']}/modules/whitelist.xml"
|
124
|
+
end
|
125
|
+
|
126
|
+
if (File.exist?(blocked_file_list))
|
127
|
+
@blocked_files = SodaUtils.ParseBlockFile(blocked_file_list)
|
128
|
+
end
|
129
|
+
|
130
|
+
if (File.exist?(whitelist_file))
|
131
|
+
@whiteList = SodaUtils.ParseWhiteFile(whitelist_file)
|
132
|
+
end
|
133
|
+
|
134
|
+
@sugarFlavor = @sugarFlavor.downcase()
|
135
|
+
|
136
|
+
if (params.key?('restart_count'))
|
137
|
+
@restart_count = params['restart_count'].to_i()
|
138
|
+
if (params.key?('restart_test'))
|
139
|
+
@restart_test = params['restart_test']
|
140
|
+
end
|
141
|
+
end
|
142
|
+
|
143
|
+
if (params['hijacks'] != nil)
|
144
|
+
@hiJacks = params['hijacks']
|
145
|
+
end
|
146
|
+
|
147
|
+
if (params.key?('sugarwait'))
|
148
|
+
@SugarWait = params['sugarwait']
|
149
|
+
end
|
150
|
+
|
151
|
+
# stack of elements allowing for parent child hierchy
|
152
|
+
# <form id='myform'><textfield name='myfield'/></form>
|
153
|
+
@parentEl = []
|
154
|
+
|
155
|
+
sigs.each do |s|
|
156
|
+
Signal.trap(s, proc { @SIGNAL_STOP = true } )
|
157
|
+
end
|
158
|
+
|
159
|
+
if (@current_os =~ /windows/i)
|
160
|
+
$win_only = true
|
161
|
+
end
|
162
|
+
|
163
|
+
@autoClick = {
|
164
|
+
"button" => true,
|
165
|
+
"link" => true,
|
166
|
+
"radio" => true
|
167
|
+
}
|
168
|
+
|
169
|
+
@params = params
|
170
|
+
err = NewBrowser()
|
171
|
+
if (err != 0)
|
172
|
+
exit(-1)
|
173
|
+
end
|
174
|
+
|
175
|
+
# this is setup to allow other skips, but there should never really
|
176
|
+
# be any other type of error to skip. The only reason why I added
|
177
|
+
# this skip is because a manager requested it. In genernal skipping
|
178
|
+
# reporting errors is not a good thing and should never ever be done!
|
179
|
+
@params['errorskip'].each do |error|
|
180
|
+
case error
|
181
|
+
when /css/i
|
182
|
+
$skip_css_errors = true
|
183
|
+
end
|
184
|
+
end
|
185
|
+
|
186
|
+
@vars['stamp'] = getStamp()
|
187
|
+
@vars['currentdate'] = getDate()
|
188
|
+
end
|
189
|
+
|
190
|
+
###############################################################################
|
191
|
+
###############################################################################
|
192
|
+
def NewBrowser()
|
193
|
+
err = 0
|
194
|
+
|
195
|
+
if ( @current_os =~ /WINDOWS/i &&
|
196
|
+
@params['browser'] =~ /ie|firefox/i )
|
197
|
+
require 'win32ole'
|
198
|
+
@autoit = WIN32OLE.new("AutoItX3.Control")
|
199
|
+
end
|
200
|
+
|
201
|
+
if (@params['browser'])
|
202
|
+
Watir::Browser.default = @params['browser']
|
203
|
+
end
|
204
|
+
|
205
|
+
if (@params['browser'] =~ /firefox/i)
|
206
|
+
for i in 0..2 do
|
207
|
+
if (@params['profile'] != nil)
|
208
|
+
result = SodaFireFox.CreateFireFoxBrowser(
|
209
|
+
{:profile => "#{@params['profile']}"})
|
210
|
+
else
|
211
|
+
result = SodaFireFox.CreateFireFoxBrowser()
|
212
|
+
end
|
213
|
+
|
214
|
+
if (result['browser'] != nil)
|
215
|
+
@browser = result['browser']
|
216
|
+
break
|
217
|
+
end
|
218
|
+
|
219
|
+
sleep(2)
|
220
|
+
end
|
221
|
+
|
222
|
+
if (@browser == nil)
|
223
|
+
SodaUtils.PrintSoda("Failed to create new firefox browser!\n",
|
224
|
+
SodaUtils::ERROR)
|
225
|
+
SodaUtils.PrintSoda("Exception Message: " +
|
226
|
+
"#{result['exception'].message}\n", SodaUtils::ERROR)
|
227
|
+
SodaUtils.PrintSoda("BackTrace: #{result['exception'].backtrace}"+
|
228
|
+
"\n", SodaUtils::ERROR)
|
229
|
+
err = -1
|
230
|
+
end
|
231
|
+
|
232
|
+
@browser.execute_script(SodaUtils::FIREFOX_JS_ERROR_CLEAR)
|
233
|
+
else
|
234
|
+
@browser = Watir::Browser.new()
|
235
|
+
end
|
236
|
+
|
237
|
+
return err
|
238
|
+
end
|
239
|
+
|
240
|
+
###############################################################################
|
241
|
+
# GetFailedTests -- Method
|
242
|
+
# This method returns a list of failed tests.
|
243
|
+
#
|
244
|
+
# Input:
|
245
|
+
# None.
|
246
|
+
#
|
247
|
+
# Output:
|
248
|
+
# returns a list of failed tests. The list can be empty of no tests
|
249
|
+
# failed.
|
250
|
+
#
|
251
|
+
###############################################################################
|
252
|
+
def GetFailedTests()
|
253
|
+
@FAILEDTESTS.uniq!()
|
254
|
+
|
255
|
+
return @FAILEDTESTS
|
256
|
+
end
|
257
|
+
public :GetFailedTests
|
258
|
+
|
259
|
+
###############################################################################
|
260
|
+
# SetGlobalVars - Method
|
261
|
+
# This method reads all the vars passed to the constructor and sets them
|
262
|
+
# up for use for all soda tests.
|
263
|
+
#
|
264
|
+
# Params:
|
265
|
+
# None.
|
266
|
+
#
|
267
|
+
# Results:
|
268
|
+
# None.
|
269
|
+
#
|
270
|
+
###############################################################################
|
271
|
+
def SetGlobalVars()
|
272
|
+
@globalVars.each do |k,v|
|
273
|
+
name = "global.#{k}"
|
274
|
+
setScriptVar(name, v)
|
275
|
+
end
|
276
|
+
end
|
277
|
+
|
278
|
+
###############################################################################
|
279
|
+
# PrintDebug -- Method
|
280
|
+
# This method only logs a message to the soda log if the debug flag is set.
|
281
|
+
#
|
282
|
+
# Params:
|
283
|
+
# str: The message to debug.
|
284
|
+
# level: The debug level to report.
|
285
|
+
#
|
286
|
+
# Results:
|
287
|
+
# Always returns 0.
|
288
|
+
#
|
289
|
+
###############################################################################
|
290
|
+
def PrintDebug(str, level = SodaUtils::LOG)
|
291
|
+
if (@debug != false)
|
292
|
+
@rep.log(str, level)
|
293
|
+
end
|
294
|
+
|
295
|
+
return 0
|
296
|
+
end
|
297
|
+
|
298
|
+
###############################################################################
|
299
|
+
# send_keys --
|
300
|
+
# This function sends keyboard keys to firefox(IE has support this method)
|
301
|
+
#
|
302
|
+
# Params:
|
303
|
+
# key_string: A string of keys to send.
|
304
|
+
#
|
305
|
+
# Results:
|
306
|
+
#
|
307
|
+
###############################################################################
|
308
|
+
def send_keys(key_string)
|
309
|
+
case Watir::Browser.default
|
310
|
+
when /ie|firefox/i
|
311
|
+
@autoit.WinActivate(@browser.title())
|
312
|
+
@autoit.Send(key_string)
|
313
|
+
else
|
314
|
+
PrintDebug("Send_keys: Unknown Browser!", SodaUtils::ERROR)
|
315
|
+
end
|
316
|
+
end
|
317
|
+
|
318
|
+
###############################################################################
|
319
|
+
# MouseClick -- Method
|
320
|
+
# This method stimulates a mouse click operation.
|
321
|
+
#
|
322
|
+
# Params:
|
323
|
+
# x: The x cord position.
|
324
|
+
# y: The y cord position.
|
325
|
+
#
|
326
|
+
# Results:
|
327
|
+
# None.
|
328
|
+
#
|
329
|
+
###############################################################################
|
330
|
+
def MouseClick(x_pos,y_pos)
|
331
|
+
@autoit.MouseClick("left", x, y)
|
332
|
+
end
|
333
|
+
|
334
|
+
###############################################################################
|
335
|
+
# getStamp -- Method
|
336
|
+
# This method creates a new formated datetime string from the current time.
|
337
|
+
#
|
338
|
+
# Params:
|
339
|
+
# None.
|
340
|
+
#
|
341
|
+
# Results:
|
342
|
+
# reutrns a formated string with the current datetime.
|
343
|
+
#
|
344
|
+
###############################################################################
|
345
|
+
def getStamp()
|
346
|
+
return Time.now().strftime("%y%m%d_%H%M%S")
|
347
|
+
end
|
348
|
+
|
349
|
+
###############################################################################
|
350
|
+
# getDate -- Method
|
351
|
+
# This method returns a new formated date string from the current time.
|
352
|
+
#
|
353
|
+
# Params:
|
354
|
+
# None.
|
355
|
+
#
|
356
|
+
# Results:
|
357
|
+
# returns a string with the current date.
|
358
|
+
#
|
359
|
+
###############################################################################
|
360
|
+
def getDate()
|
361
|
+
return Time.now().strftime("%m/%d/%Y")
|
362
|
+
end
|
363
|
+
|
364
|
+
###############################################################################
|
365
|
+
# setScriptVar -- Method
|
366
|
+
# This method sets variables used during script execution by the scripts
|
367
|
+
# themselves.
|
368
|
+
#
|
369
|
+
# Params:
|
370
|
+
# name: The key in the @vars to set.
|
371
|
+
# value: The new value to the for the given key.
|
372
|
+
#
|
373
|
+
# Results:
|
374
|
+
# None.
|
375
|
+
#
|
376
|
+
###############################################################################
|
377
|
+
def setScriptVar(name, value)
|
378
|
+
@vars[name] = value
|
379
|
+
msg = "Setting key: \"#{name}\" =>"
|
380
|
+
|
381
|
+
if (value.instance_of?(Hash))
|
382
|
+
msg << " Hash:{"
|
383
|
+
value.each do |k ,v|
|
384
|
+
msg << "'#{k}'=>'#{v}',"
|
385
|
+
end
|
386
|
+
msg = msg.chop()
|
387
|
+
msg << "}\n"
|
388
|
+
else
|
389
|
+
msg << " \"#{value}\"\n"
|
390
|
+
end
|
391
|
+
|
392
|
+
PrintDebug(msg)
|
393
|
+
end
|
394
|
+
|
395
|
+
###############################################################################
|
396
|
+
# getScriptVar -- Method
|
397
|
+
# This method retrieves variables used during script execution if the
|
398
|
+
# variable is not set then the default value is returned variables are
|
399
|
+
# specified in a script as {@myvar} to set this variable use var='myvar'
|
400
|
+
# for CSV variables it would be {@record.csvvar}
|
401
|
+
# The following attribues may have variables used within them
|
402
|
+
# *assert
|
403
|
+
# *accessor attributes (href, id, value ...)
|
404
|
+
# *contains
|
405
|
+
#
|
406
|
+
# Params:
|
407
|
+
# name: The name of the var to get the value from.
|
408
|
+
# default: If the value isn't already set then it is set to this value.
|
409
|
+
#
|
410
|
+
# Results:
|
411
|
+
# returns the value for the given name.
|
412
|
+
#
|
413
|
+
# Notes:
|
414
|
+
# This method will also overwrite any csv value of the key for that value
|
415
|
+
# is in the @hiJacks hash for this class.
|
416
|
+
#
|
417
|
+
###############################################################################
|
418
|
+
def getScriptVar(name, default='')
|
419
|
+
val = default
|
420
|
+
names = nil
|
421
|
+
is_csv = false
|
422
|
+
org_name = name
|
423
|
+
tmp_name = org_name.gsub(/^\./, "")
|
424
|
+
|
425
|
+
# if it contains a '.' it must be a CSV variable so it is stored as a
|
426
|
+
# hash
|
427
|
+
if ( (name.index('.')) && (name !~ /^global/) )
|
428
|
+
names = name.split('.')
|
429
|
+
name = names[0]
|
430
|
+
is_csv = true
|
431
|
+
end
|
432
|
+
|
433
|
+
# make sure we have a variable set
|
434
|
+
if (@vars.key?(name))
|
435
|
+
# if we have an array for names it means it was a CSV variable
|
436
|
+
if (names)
|
437
|
+
val = @vars[name][names[1]]
|
438
|
+
else
|
439
|
+
val = @vars[name]
|
440
|
+
end
|
441
|
+
else
|
442
|
+
begin
|
443
|
+
val = "Soda unknown script key: \"#{tmp_name}\"!"
|
444
|
+
msg = "Failed to find script variable by name: \"#{tmp_name}\"!\n"
|
445
|
+
@rep.ReportFailure(msg)
|
446
|
+
raise(msg)
|
447
|
+
rescue Exception => e
|
448
|
+
@rep.ReportException(e, false, false)
|
449
|
+
ensure
|
450
|
+
|
451
|
+
end
|
452
|
+
end
|
453
|
+
|
454
|
+
if (@hiJacks.key?(org_name))
|
455
|
+
PrintDebug("High Jacking CSV variable: \"#{org_name}\" from value:" +
|
456
|
+
" \"#{val}\" to \"#{@hiJacks["#{org_name}"]}\"\n")
|
457
|
+
val = @hiJacks["#{org_name}"]
|
458
|
+
else
|
459
|
+
PrintDebug("Value for \"#{tmp_name}\" => \"#{val}\".\n")
|
460
|
+
end
|
461
|
+
|
462
|
+
val = "" if (val == nil) # default it to be an empty string. #
|
463
|
+
|
464
|
+
return val
|
465
|
+
end
|
466
|
+
|
467
|
+
###############################################################################
|
468
|
+
# getField -- Method
|
469
|
+
# This method gets the field based on the event from the page.
|
470
|
+
#
|
471
|
+
# Params:
|
472
|
+
# event: This is the event to use to get the field.
|
473
|
+
# flag: If true will cause this function to wait for the event.
|
474
|
+
#
|
475
|
+
# Results:
|
476
|
+
#
|
477
|
+
###############################################################################
|
478
|
+
def getField(event, flag = true)
|
479
|
+
str = nil
|
480
|
+
field = nil
|
481
|
+
|
482
|
+
# this is to handle how the IE dom accesses links #
|
483
|
+
if ( (Watir::Browser.default =~ /ie/i) && (event.key?('href')) )
|
484
|
+
tmp_href = event['href']
|
485
|
+
event = SodaUtils.IEConvertHref(event, @browser.url())
|
486
|
+
@rep.log("Converted Soda test href: '#{tmp_href}' to IE href:"+
|
487
|
+
" '#{event['href']}'.\n")
|
488
|
+
end
|
489
|
+
str = generateWatirObjectStr(event)
|
490
|
+
|
491
|
+
# if the timeout is set use the specified timeout for accessing the
|
492
|
+
# field otherwise allow 15 seconds
|
493
|
+
timeout = (event.key?('timeout'))? Integer(event['timeout']): 15
|
494
|
+
required = (event.key?('required'))? SodaField.getStringTrue(event['required']): true
|
495
|
+
|
496
|
+
event['required'] = required
|
497
|
+
|
498
|
+
if (event.key?('exist'))
|
499
|
+
event['exists'] = event['exist']
|
500
|
+
end
|
501
|
+
|
502
|
+
if (event.key?('exists'))
|
503
|
+
exists = getStringBool(event['exists'])
|
504
|
+
|
505
|
+
if (exists == true)
|
506
|
+
field = waitFor(eval(str), event['do'], timeout, true)
|
507
|
+
|
508
|
+
if (field != nil)
|
509
|
+
@rep.Assert(true, "#{event['do']} element exists.",
|
510
|
+
@currentTestFile)
|
511
|
+
else
|
512
|
+
@rep.Assert(false, "Failed to find #{event['do']} element!",
|
513
|
+
@currentTestFile, "#{event['line_number']}")
|
514
|
+
@FAILEDTESTS.push(@currentTestFile)
|
515
|
+
end
|
516
|
+
else
|
517
|
+
field = waitFor(eval(str), event['do'], timeout, false)
|
518
|
+
if (field == nil)
|
519
|
+
@rep.Assert(true, "#{event['do']} element does not exist as "+
|
520
|
+
"expected.", @currentTestFile)
|
521
|
+
else
|
522
|
+
@rep.Assert(false, "#{event['do']} exists when it is not "+
|
523
|
+
"expected to!", @currentTestFile, "#{event['line_number']}")
|
524
|
+
@FAILEDTESTS.push(@currentTestFile)
|
525
|
+
end
|
526
|
+
end
|
527
|
+
else
|
528
|
+
# use for wait tag
|
529
|
+
if (flag == false)
|
530
|
+
field = waitFor(eval(str), event['do'], timeout, required, false)
|
531
|
+
else
|
532
|
+
# get the field
|
533
|
+
field = waitFor(eval(str), event['do'], timeout, required)
|
534
|
+
end
|
535
|
+
end
|
536
|
+
|
537
|
+
if ( (required != true) && (field == nil) )
|
538
|
+
@rep.log("Element not found, but was tagged as: required ="+
|
539
|
+
" \"#{required}\".\n")
|
540
|
+
end
|
541
|
+
|
542
|
+
return field
|
543
|
+
end
|
544
|
+
|
545
|
+
###############################################################################
|
546
|
+
# generateWatirObjectStr -- Method
|
547
|
+
# This function generates ruby watir code on the fly based on the event.
|
548
|
+
#
|
549
|
+
# Params:
|
550
|
+
# event: A soda event.
|
551
|
+
#
|
552
|
+
# Results:
|
553
|
+
# returns a string of ruby/watir code.
|
554
|
+
#
|
555
|
+
###############################################################################
|
556
|
+
def generateWatirObjectStr(event)
|
557
|
+
str = ""
|
558
|
+
|
559
|
+
# the 'do' is the field to access at this point
|
560
|
+
fun = event['do'];
|
561
|
+
|
562
|
+
# if there is a parent Element we are going to use that #
|
563
|
+
if (@parentEl.length > 0)
|
564
|
+
str = '@parentEl[@parentEl.length - 1]'
|
565
|
+
else
|
566
|
+
# otherwise the browser is the parent
|
567
|
+
str = '@browser'
|
568
|
+
end
|
569
|
+
|
570
|
+
str += ".send(:#{fun} "
|
571
|
+
|
572
|
+
# sodalookups contains how each field may be accessed
|
573
|
+
$sodalookups[fun].each do |how, avail|
|
574
|
+
if (!avail)
|
575
|
+
next
|
576
|
+
end
|
577
|
+
|
578
|
+
if (event.key?(how))
|
579
|
+
# replace any variables in how we are going to use it
|
580
|
+
# (useful for dynamic links)
|
581
|
+
event[how] = replaceVars(event[how])
|
582
|
+
regex = stringToRegex(event[how])
|
583
|
+
quote = true
|
584
|
+
|
585
|
+
if (regex != event[how])
|
586
|
+
quote = false
|
587
|
+
end
|
588
|
+
|
589
|
+
curhow = event[how]
|
590
|
+
if (quote)
|
591
|
+
curhow = "'#{event[how]}'"
|
592
|
+
end
|
593
|
+
|
594
|
+
# despite documentation forms don't support multiple attributes
|
595
|
+
if (fun == 'form')
|
596
|
+
str += ",:#{how}, #{curhow}"
|
597
|
+
break
|
598
|
+
end
|
599
|
+
|
600
|
+
# support for accessing elements by multiple attributes
|
601
|
+
str += ",:#{how}=>#{curhow}"
|
602
|
+
end
|
603
|
+
# if we have an index which specifies which one to return if there
|
604
|
+
# are more than one
|
605
|
+
# if event.key?('index')
|
606
|
+
# str += ",:index=>#{event['index']}"
|
607
|
+
# end
|
608
|
+
end # end each #
|
609
|
+
|
610
|
+
str += ")"
|
611
|
+
|
612
|
+
return str
|
613
|
+
end
|
614
|
+
|
615
|
+
###############################################################################
|
616
|
+
# waitFor -- Method
|
617
|
+
# Waits for a field to be present this ensures that a field is on the page
|
618
|
+
# when we expect it to *field is the field we want *name is a human
|
619
|
+
# readable name for the field *timeout is the number of seconds we are
|
620
|
+
# willing to wait for the field if timeout is set to 0 or -1 then we
|
621
|
+
# won't raise an exception if we can't find the field and we consider the
|
622
|
+
# field optional.
|
623
|
+
#
|
624
|
+
# Params:
|
625
|
+
# field: This is the name of the field on the page.
|
626
|
+
# name: The human readable field name.
|
627
|
+
# timeout: Number of seconds to wait for the field.
|
628
|
+
# required:
|
629
|
+
# flag:
|
630
|
+
#
|
631
|
+
# Results:
|
632
|
+
# returns nil on error, or field on success.
|
633
|
+
#
|
634
|
+
###############################################################################
|
635
|
+
def waitFor(field, name, timeout = 15, required = true, flag = true)
|
636
|
+
start_time = Time.now
|
637
|
+
result = nil
|
638
|
+
found_field = false
|
639
|
+
|
640
|
+
until (found_field = field.exists?) do
|
641
|
+
sleep(0.5)
|
642
|
+
# if the timeout is > 0 then we really wanted the field to be there
|
643
|
+
# so raise an exception otherwise the field is considered optional
|
644
|
+
# used for "wait" tag
|
645
|
+
|
646
|
+
if ( (Time.now - start_time > timeout) && (found_field != true))
|
647
|
+
if (flag == false)
|
648
|
+
msg = "waitFor: Element not found: \"#{name}\"!\n"
|
649
|
+
@rep.log(msg)
|
650
|
+
break
|
651
|
+
end
|
652
|
+
|
653
|
+
if ($link_not_assert)
|
654
|
+
@rep.log("Assertion Passed\n");
|
655
|
+
$link_not_assert = false
|
656
|
+
break
|
657
|
+
elsif (required && (found_field != true))
|
658
|
+
@rep.log("waitFor: Element not found: \"#{name}\""+
|
659
|
+
" Timedout after #{timeout} seconds!\n")
|
660
|
+
@FAILEDTESTS.push(@currentTestFile)
|
661
|
+
break
|
662
|
+
else
|
663
|
+
break
|
664
|
+
end
|
665
|
+
end
|
666
|
+
end
|
667
|
+
|
668
|
+
if (flag == false)
|
669
|
+
@rep.log("waitFor found Element: \"#{name}\".\n");
|
670
|
+
end
|
671
|
+
|
672
|
+
result = field if (found_field)
|
673
|
+
|
674
|
+
return result
|
675
|
+
end
|
676
|
+
|
677
|
+
###############################################################################
|
678
|
+
# waitByMultipleCondition -- Method
|
679
|
+
# This method waits until the multiple condition is matchedv.
|
680
|
+
#
|
681
|
+
# Params:
|
682
|
+
# event: The event to check.
|
683
|
+
# timeout: The number of seconds to wait.
|
684
|
+
#
|
685
|
+
# Results:
|
686
|
+
# None.
|
687
|
+
#
|
688
|
+
# Notes:
|
689
|
+
# This method looks like a total hack, need to revist this later.
|
690
|
+
#
|
691
|
+
###############################################################################
|
692
|
+
def waitByMultipleCondition(event, timeout = 10)
|
693
|
+
case event['do']
|
694
|
+
when "textfield"
|
695
|
+
event['do'] = 'text_field'
|
696
|
+
when "textarea"
|
697
|
+
event['do'] = 'text_field'
|
698
|
+
when "select"
|
699
|
+
event['do'] = 'select_list'
|
700
|
+
when "filefield"
|
701
|
+
event['do'] = 'file_field'
|
702
|
+
end
|
703
|
+
|
704
|
+
event['timeout'] = timeout
|
705
|
+
@curEl = getField(event, false)
|
706
|
+
|
707
|
+
if (event.key?('children'))
|
708
|
+
@parentEl.push(@curEl)
|
709
|
+
event['children'].each do |sub_event|
|
710
|
+
waitByMultipleCondition(sub_event, event['timeout'])
|
711
|
+
end
|
712
|
+
end
|
713
|
+
|
714
|
+
@parentEl.pop()
|
715
|
+
end
|
716
|
+
|
717
|
+
###############################################################################
|
718
|
+
# getScript -- Method
|
719
|
+
# This method loads and soda XML script and parses it and returns the
|
720
|
+
# Soda Meta Data.
|
721
|
+
#
|
722
|
+
# Params:
|
723
|
+
# file: A soda xml test file.
|
724
|
+
# is_restart: true/false, tells us that this is a restart test.
|
725
|
+
#
|
726
|
+
# Results:
|
727
|
+
# on success returns a LibXML::Parser Document, or nil on error.
|
728
|
+
#
|
729
|
+
###############################################################################
|
730
|
+
def getScript(file, is_restart = false)
|
731
|
+
script = nil
|
732
|
+
valid_xml = true
|
733
|
+
script_check = false
|
734
|
+
err = 0
|
735
|
+
|
736
|
+
if (!File.extname(file) == '.xml')
|
737
|
+
msg = "Failed trying to parse file: \"#{file}\": Not a valid " +
|
738
|
+
" XML file!\n"
|
739
|
+
@rep.ReportFailure(msg)
|
740
|
+
script = nil
|
741
|
+
valid_xml = false
|
742
|
+
end
|
743
|
+
|
744
|
+
if (valid_xml && !@restart_test_running && file != @last_file &&
|
745
|
+
@non_lib_test_count >= @restart_count)
|
746
|
+
RestartBrowserTest()
|
747
|
+
end
|
748
|
+
|
749
|
+
if (valid_xml)
|
750
|
+
$run_script = file
|
751
|
+
PrintDebug("Parsing Soda test file: \"#{file}\".\n")
|
752
|
+
begin
|
753
|
+
checker = SodaTestCheck.new(file, @rep)
|
754
|
+
script_check = checker.Check()
|
755
|
+
|
756
|
+
if (!script_check)
|
757
|
+
script = nil
|
758
|
+
@rep.IncSkippedTest()
|
759
|
+
else
|
760
|
+
script = SodaXML.new.parse(file)
|
761
|
+
end
|
762
|
+
rescue Exception => e
|
763
|
+
@rep.ReportException(e, true, file)
|
764
|
+
ensure
|
765
|
+
end
|
766
|
+
end
|
767
|
+
|
768
|
+
dir = File.dirname(file)
|
769
|
+
if (dir !~ /lib/)
|
770
|
+
if(!is_restart && !@restart_test_running && file != @last_test)
|
771
|
+
@non_lib_test_count += 1
|
772
|
+
PrintDebug("Test since last restart: #{@non_lib_test_count +1}.\n")
|
773
|
+
end
|
774
|
+
end
|
775
|
+
|
776
|
+
return script
|
777
|
+
end
|
778
|
+
|
779
|
+
###############################################################################
|
780
|
+
# RestartBrowserTest -- Method
|
781
|
+
# This method checks to see if the browser needs to be restarted.
|
782
|
+
#
|
783
|
+
# Input:
|
784
|
+
# None.
|
785
|
+
#
|
786
|
+
# Output:
|
787
|
+
# None.
|
788
|
+
#
|
789
|
+
###############################################################################
|
790
|
+
def RestartBrowserTest()
|
791
|
+
return 0 if (@restart_count < 1)
|
792
|
+
|
793
|
+
if (@non_lib_test_count >= @restart_count)
|
794
|
+
@rep.log("Restarting browser.\n")
|
795
|
+
@browser.close()
|
796
|
+
sleep(1)
|
797
|
+
|
798
|
+
err = NewBrowser()
|
799
|
+
if (err != 0)
|
800
|
+
@rep.ReportFailure("Failed to restart browser!\n")
|
801
|
+
end
|
802
|
+
@rep.log("Finished: Browser restart.\n")
|
803
|
+
@non_lib_test_count = 0
|
804
|
+
|
805
|
+
if (!@restart_test.empty?)
|
806
|
+
parent_test = @currentTestFile
|
807
|
+
restart_data = getScript(@restart_test, true)
|
808
|
+
if (restart_data != nil)
|
809
|
+
@currentTestFile = @restart_test
|
810
|
+
@restart_test_running = true
|
811
|
+
@rep.log("Executing restart test: '#{@restart_test}'\n")
|
812
|
+
handleEvents(restart_data)
|
813
|
+
@restart_test_running = false
|
814
|
+
@currentTestFile = parent_test
|
815
|
+
@rep.log("Finished restart test: '#{@restart_test}'\n")
|
816
|
+
end
|
817
|
+
end
|
818
|
+
end
|
819
|
+
end
|
820
|
+
|
821
|
+
###############################################################################
|
822
|
+
# getDirScript -- Method
|
823
|
+
# This method goes into directory and load xml scripts.
|
824
|
+
#
|
825
|
+
# Params:
|
826
|
+
# file: This is the file to open.
|
827
|
+
#
|
828
|
+
# Results:
|
829
|
+
# None.
|
830
|
+
#
|
831
|
+
# Notes:
|
832
|
+
# Using recursion... This should be revisited for a better way.
|
833
|
+
#
|
834
|
+
###############################################################################
|
835
|
+
def getDirScript(file)
|
836
|
+
test_count = 0
|
837
|
+
results = 0
|
838
|
+
|
839
|
+
file = File.expand_path(file)
|
840
|
+
|
841
|
+
if (File.directory?(file))
|
842
|
+
files = []
|
843
|
+
fd = Dir.open(file)
|
844
|
+
fd.each do |f|
|
845
|
+
files.push("#{file}/#{f}") if (f =~ /\.xml$/i)
|
846
|
+
end
|
847
|
+
fd.close()
|
848
|
+
|
849
|
+
if (files.empty?)
|
850
|
+
@rep.log("No tests found in directory: '#{file}'!\n",
|
851
|
+
SodaUtils::WARN)
|
852
|
+
return nil
|
853
|
+
end
|
854
|
+
|
855
|
+
test_count = files.length()
|
856
|
+
@rep.log("Fileset: '#{file}' contains #{test_count} files.\n")
|
857
|
+
|
858
|
+
files.each do |f|
|
859
|
+
getDirScript(f)
|
860
|
+
end
|
861
|
+
elsif (File.file?(file))
|
862
|
+
if (!(remBlockScript(file)) &&
|
863
|
+
((file !~ /^setup/) || (file !~ /^cleanup/) ) )
|
864
|
+
@rep.log("Starting new soda test file: \"#{file}\".\n")
|
865
|
+
|
866
|
+
if (file !~ /lib/i)
|
867
|
+
if (@non_lib_test_count >= @restart_count && file != @last_test)
|
868
|
+
RestartBrowserTest()
|
869
|
+
end
|
870
|
+
|
871
|
+
@non_lib_test_count += 1
|
872
|
+
@last_test = file
|
873
|
+
end
|
874
|
+
|
875
|
+
script = getScript(file)
|
876
|
+
if (script != nil)
|
877
|
+
parent_test_file = @currentTestFile
|
878
|
+
@currentTestFile = file
|
879
|
+
@rep.IncTestCount()
|
880
|
+
results = handleEvents(script)
|
881
|
+
PrintDebug("Test since last restart: #{@non_lib_test_count +1}.\n")
|
882
|
+
|
883
|
+
if (results != 0)
|
884
|
+
@FAILEDTESTS.push(@currentTestFile)
|
885
|
+
end
|
886
|
+
@currentTestFile = parent_test_file
|
887
|
+
else
|
888
|
+
msg = "Failed opening script file: \"#{file}\"!\n"
|
889
|
+
@rep.ReportFailure(msg)
|
890
|
+
end
|
891
|
+
end
|
892
|
+
end
|
893
|
+
end
|
894
|
+
|
895
|
+
###############################################################################
|
896
|
+
# remBlockScript -- Method
|
897
|
+
# This method checks to see of the test file is in the
|
898
|
+
# blockScriptsList.txt to decide if the test can be ran.
|
899
|
+
#
|
900
|
+
# Params:
|
901
|
+
# file: This is the soda test file that were are checking to see of we can
|
902
|
+
# run or not.
|
903
|
+
#
|
904
|
+
# Results:
|
905
|
+
# returns true if the file is to be blocked, else false.
|
906
|
+
#
|
907
|
+
###############################################################################
|
908
|
+
def remBlockScript(test_file)
|
909
|
+
result = false
|
910
|
+
|
911
|
+
@blocked_files.each do |bhash|
|
912
|
+
tmp_file = File.basename(test_file)
|
913
|
+
if (tmp_file =~ /#{bhash['testfile']}/)
|
914
|
+
@rep.log("Blocklist: blocking file: \"#{test_file}\".\n")
|
915
|
+
result = true
|
916
|
+
break
|
917
|
+
end
|
918
|
+
end
|
919
|
+
|
920
|
+
return result
|
921
|
+
end
|
922
|
+
|
923
|
+
###############################################################################
|
924
|
+
# getRightCSV -- Method
|
925
|
+
# This method replaces the default csv with specified event.
|
926
|
+
#
|
927
|
+
# Params:
|
928
|
+
# event: This is the event to replace the csv with.
|
929
|
+
#
|
930
|
+
# Results:
|
931
|
+
# None.
|
932
|
+
#
|
933
|
+
###############################################################################
|
934
|
+
def getRightCSV(event)
|
935
|
+
for csv in @newCSV
|
936
|
+
csv.each do |runfile, runcsv|
|
937
|
+
if (@fileStack[@fileStack.length - 1] == runfile)
|
938
|
+
event['file'] = runcsv
|
939
|
+
@newCSV.delete(runfile)
|
940
|
+
end
|
941
|
+
end
|
942
|
+
end
|
943
|
+
end
|
944
|
+
|
945
|
+
###############################################################################
|
946
|
+
# getEvents -- Method
|
947
|
+
# This methos returns a list of events. Certain events may need to be
|
948
|
+
# expanded into multiple events.
|
949
|
+
#
|
950
|
+
# Params:
|
951
|
+
# event: This event to get...
|
952
|
+
#
|
953
|
+
# Results:
|
954
|
+
# returns a hash of events.
|
955
|
+
#
|
956
|
+
###############################################################################
|
957
|
+
def getEvents(event)
|
958
|
+
events = []
|
959
|
+
seed = nil
|
960
|
+
|
961
|
+
# expand lists into multiple events #
|
962
|
+
if (event.key?('list'))
|
963
|
+
seed = Hash.new()
|
964
|
+
|
965
|
+
event.each do |k,v|
|
966
|
+
if (k == 'list' || k == 'by')
|
967
|
+
next
|
968
|
+
end
|
969
|
+
seed[k] = v
|
970
|
+
end
|
971
|
+
|
972
|
+
event['list'].each do |k,v|
|
973
|
+
cur = seed.dup
|
974
|
+
cur[event['by']] = k
|
975
|
+
cur['set'] = v
|
976
|
+
events.push(cur)
|
977
|
+
end
|
978
|
+
else
|
979
|
+
events.push(event)
|
980
|
+
end
|
981
|
+
|
982
|
+
return events
|
983
|
+
end
|
984
|
+
|
985
|
+
###############################################################################
|
986
|
+
# replaceVars -- Method
|
987
|
+
# This method replaces a {@varname} with the appropriate variable.
|
988
|
+
#
|
989
|
+
# Params:
|
990
|
+
# str: The string to replace words in.
|
991
|
+
# default: The default to replace with.
|
992
|
+
#
|
993
|
+
# Results:
|
994
|
+
# returns an empty string if the var is the csv file is nothing, else a
|
995
|
+
# new string with the vars replaced.
|
996
|
+
#
|
997
|
+
###############################################################################
|
998
|
+
def replaceVars(str, default='')
|
999
|
+
org_str = str
|
1000
|
+
vars_hash = Hash.new()
|
1001
|
+
result = "#{str}".scan(/\{@[\w\.]+\}/i)
|
1002
|
+
|
1003
|
+
result.each do |var|
|
1004
|
+
next if ( (var == nil) or (var.empty?) )
|
1005
|
+
var = var.gsub(/^\{@/, "")
|
1006
|
+
var = var.gsub(/\}$/, "")
|
1007
|
+
tmp = getScriptVar(var, default)
|
1008
|
+
|
1009
|
+
if (tmp == nil)
|
1010
|
+
tmp = "Unknown Var: '#{var}'"
|
1011
|
+
@rep.ReportFailure("Error trying to access an unknown script var:"+
|
1012
|
+
" '#{var}'!\n")
|
1013
|
+
end
|
1014
|
+
|
1015
|
+
vars_hash[var] = tmp
|
1016
|
+
end
|
1017
|
+
|
1018
|
+
vars_hash.each do |k, v|
|
1019
|
+
str = str.gsub(/\{@#{k}\}/, v)
|
1020
|
+
end
|
1021
|
+
|
1022
|
+
if (org_str != str)
|
1023
|
+
PrintDebug("Replacing string '#{org_str}' with '#{str}'\n")
|
1024
|
+
end
|
1025
|
+
|
1026
|
+
return str
|
1027
|
+
end
|
1028
|
+
|
1029
|
+
###############################################################################
|
1030
|
+
# stringToRegex -- Method
|
1031
|
+
# This method creates a Regexp object from a string.
|
1032
|
+
#
|
1033
|
+
# Params:
|
1034
|
+
# str: The string to convert to a regex.
|
1035
|
+
#
|
1036
|
+
# Results:
|
1037
|
+
# returns the passed string if it is not a regex str, else a new regex
|
1038
|
+
# object is returned.
|
1039
|
+
#
|
1040
|
+
###############################################################################
|
1041
|
+
def stringToRegex(str)
|
1042
|
+
result = nil
|
1043
|
+
|
1044
|
+
if (SodaUtils.isRegex(str))
|
1045
|
+
result = SodaUtils.CreateRegexFromStr(str)
|
1046
|
+
if (result == nil)
|
1047
|
+
@rep.ReportFailure("Failed trying to convert string to regex:"+
|
1048
|
+
" String: '#{str}'!\n")
|
1049
|
+
end
|
1050
|
+
else
|
1051
|
+
result = str
|
1052
|
+
end
|
1053
|
+
|
1054
|
+
return result
|
1055
|
+
end
|
1056
|
+
|
1057
|
+
###############################################################################
|
1058
|
+
# assertPage -- Method
|
1059
|
+
# This method checks to see of the browser contains any text for known
|
1060
|
+
# errors. It also looks to make sure anything in the whitelist isn't
|
1061
|
+
# reported as a error.
|
1062
|
+
#
|
1063
|
+
# Input:
|
1064
|
+
# None.
|
1065
|
+
#
|
1066
|
+
# Output:
|
1067
|
+
# None.
|
1068
|
+
#
|
1069
|
+
###############################################################################
|
1070
|
+
def assertPage()
|
1071
|
+
data = []
|
1072
|
+
found_error = false
|
1073
|
+
page_strs_to_replace = [
|
1074
|
+
'Expiration Notice:', 'Notice: Your license expires',
|
1075
|
+
'Warning: Please upgrade',
|
1076
|
+
'(Fatal|Error): Your license expired|',
|
1077
|
+
'isError', 'errors' ,'ErrorLink'
|
1078
|
+
]
|
1079
|
+
page_strs_to_replace2 = [
|
1080
|
+
'Warning: Your email settings are not configured to send email',
|
1081
|
+
'Warning: Missing username and password',
|
1082
|
+
'Warning: You are modifying your automatic',
|
1083
|
+
'Warning: Auto import must be enabled when automatically'+
|
1084
|
+
' creating cases'
|
1085
|
+
]
|
1086
|
+
|
1087
|
+
crazyEvilIETabHack()
|
1088
|
+
@browser.wait()
|
1089
|
+
|
1090
|
+
begin
|
1091
|
+
text = @browser.text
|
1092
|
+
rescue Exception => e
|
1093
|
+
@rep.ReportException(e, true)
|
1094
|
+
text = ""
|
1095
|
+
ensure
|
1096
|
+
|
1097
|
+
end
|
1098
|
+
|
1099
|
+
text = text.gsub(/^\n/, "")
|
1100
|
+
|
1101
|
+
page_strs_to_replace.each do |reg|
|
1102
|
+
text = text.gsub(/#{reg}/i, '')
|
1103
|
+
end
|
1104
|
+
|
1105
|
+
page_strs_to_replace2.each do |reg|
|
1106
|
+
text = text.gsub(/#{reg}/, '')
|
1107
|
+
end
|
1108
|
+
|
1109
|
+
@whiteList.each do |hash|
|
1110
|
+
text = text.gsub(/#{hash['data']}/, '')
|
1111
|
+
end
|
1112
|
+
|
1113
|
+
data = text.split(/\n/)
|
1114
|
+
data.each do |line|
|
1115
|
+
case (line)
|
1116
|
+
when /(Notice:.*line.*)/i
|
1117
|
+
@rep.ReportFailure("Found error in page HTML: '#{$1}'\n")
|
1118
|
+
found_error = true
|
1119
|
+
when /(Warning:)/i
|
1120
|
+
@rep.ReportFailure("Found error in page HTML: '#{$1}'\n")
|
1121
|
+
found_error = true
|
1122
|
+
when /(.*Error:.*line.*)/i
|
1123
|
+
@rep.ReportFailure("Found error in page HTML: '#{$1}'\n")
|
1124
|
+
found_error = true
|
1125
|
+
when/(Error retrieving)/i
|
1126
|
+
@rep.ReportFailure("Found error in page HTML: '#{$1}'\n")
|
1127
|
+
found_error = true
|
1128
|
+
when /(SQL Error)/i
|
1129
|
+
@rep.ReportFailure("Found error in page HTML: '#{$1}'\n")
|
1130
|
+
found_error = true
|
1131
|
+
end
|
1132
|
+
end
|
1133
|
+
|
1134
|
+
if (found_error)
|
1135
|
+
@FAILEDTESTS.push(@currentTestFile)
|
1136
|
+
end
|
1137
|
+
|
1138
|
+
end
|
1139
|
+
|
1140
|
+
##############################################################################
|
1141
|
+
# kindsOfBrowserAssert -- Method
|
1142
|
+
# This method does an assert on the text contained in the web browser.
|
1143
|
+
# The assert can be either a regexp or a string.
|
1144
|
+
#
|
1145
|
+
# Input:
|
1146
|
+
# event: This is a soda event.
|
1147
|
+
# flag: true or false, for an assert or an assertnot
|
1148
|
+
#
|
1149
|
+
# Output:
|
1150
|
+
# returns -1 on error else 0 on success.
|
1151
|
+
#
|
1152
|
+
###############################################################################
|
1153
|
+
def kindsOfBrowserAssert(event, flag = true)
|
1154
|
+
msg = "Unknown Browser Assert!"
|
1155
|
+
match = nil
|
1156
|
+
ass = nil
|
1157
|
+
contains = ""
|
1158
|
+
is_regex = false
|
1159
|
+
result = 0
|
1160
|
+
|
1161
|
+
if (event['assert'].kind_of? Regexp)
|
1162
|
+
is_regex = true
|
1163
|
+
contains = event['assert'].to_s()
|
1164
|
+
|
1165
|
+
if (event['assert'] != nil)
|
1166
|
+
match = event['assert'].match(@browser.text)
|
1167
|
+
if (match != nil)
|
1168
|
+
ass = true
|
1169
|
+
else
|
1170
|
+
ass = false
|
1171
|
+
end
|
1172
|
+
else
|
1173
|
+
@rep.ReportFailure("Failed to create regex!\n")
|
1174
|
+
e_dump = SodaUtils.DumpEvent(event)
|
1175
|
+
@rep.log("Event Dump: #{e_dump}!\n", SodaUtils::EVENT)
|
1176
|
+
ass = false
|
1177
|
+
result = -1
|
1178
|
+
end
|
1179
|
+
else
|
1180
|
+
contains = replaceVars(event['assert'] )
|
1181
|
+
# assert the text in specified area
|
1182
|
+
if (@parentEl.length > 0)
|
1183
|
+
ass = @parentEl[@parentEl.length-1].text.include?(contains)
|
1184
|
+
else
|
1185
|
+
ass = @browser.text.include?(contains)
|
1186
|
+
end
|
1187
|
+
end
|
1188
|
+
|
1189
|
+
if (flag)
|
1190
|
+
if (!is_regex)
|
1191
|
+
msg = "Checking that the Browser does contain the text: "+
|
1192
|
+
"\"#{contains}\""
|
1193
|
+
else
|
1194
|
+
msg = "Checking that the Browser does match regex: "+
|
1195
|
+
"\"#{contains}\""
|
1196
|
+
end
|
1197
|
+
|
1198
|
+
result = @rep.Assert(ass, msg, @currentTestFile,
|
1199
|
+
"#{event['line_number']}")
|
1200
|
+
if (result != 0)
|
1201
|
+
@FAILEDTESTS.push(@currentTestFile)
|
1202
|
+
end
|
1203
|
+
else
|
1204
|
+
if (!is_regex)
|
1205
|
+
msg = "Checking that browser does not contain text:"+
|
1206
|
+
" \"#{contains}\" in page."
|
1207
|
+
else
|
1208
|
+
msg = "Checking that browser regex doesn not match: "+
|
1209
|
+
" \"#{contains}\" in page."
|
1210
|
+
end
|
1211
|
+
|
1212
|
+
result = @rep.Assert(!ass, msg, @currentTestFile,
|
1213
|
+
"#{event['line_number']}")
|
1214
|
+
if (result != 0)
|
1215
|
+
@FAILEDTESTS.push(@currentTestFile)
|
1216
|
+
end
|
1217
|
+
end
|
1218
|
+
|
1219
|
+
return result
|
1220
|
+
end
|
1221
|
+
|
1222
|
+
###############################################################################
|
1223
|
+
# getStringBool -- Method
|
1224
|
+
# This method checks to see of the value passed to it proves to be positive
|
1225
|
+
# in most any way.
|
1226
|
+
#
|
1227
|
+
# Params:
|
1228
|
+
# value: This is a string that will prove something true or false.
|
1229
|
+
#
|
1230
|
+
# Results:
|
1231
|
+
# returns true if the value is a form of being 'positive', or false.
|
1232
|
+
# If the value isn't a string then the value is just returned....
|
1233
|
+
#
|
1234
|
+
# Notes:
|
1235
|
+
# This is a total hack, we should be throw an exception if the value is
|
1236
|
+
# something other then a string... Will come back to this later...
|
1237
|
+
#
|
1238
|
+
###############################################################################
|
1239
|
+
def getStringBool(value)
|
1240
|
+
if (value.is_a?(String))
|
1241
|
+
value.downcase!
|
1242
|
+
|
1243
|
+
if (value == 'true' or value == 'yes' or value == '1')
|
1244
|
+
return true
|
1245
|
+
else
|
1246
|
+
return false
|
1247
|
+
end
|
1248
|
+
end
|
1249
|
+
|
1250
|
+
return value
|
1251
|
+
end
|
1252
|
+
|
1253
|
+
###############################################################################
|
1254
|
+
# checkSelectList -- Method
|
1255
|
+
# This method checks to see if a string exisits in a list of some kind.
|
1256
|
+
#
|
1257
|
+
# Params:
|
1258
|
+
# list: ???
|
1259
|
+
# str: A string to check for in the list.
|
1260
|
+
#
|
1261
|
+
# Results:
|
1262
|
+
# returns true of the string is found or false if it is not.
|
1263
|
+
#
|
1264
|
+
###############################################################################
|
1265
|
+
def checkSelectList(list, str)
|
1266
|
+
list.each do |i|
|
1267
|
+
if (i == str)
|
1268
|
+
return true
|
1269
|
+
end
|
1270
|
+
end
|
1271
|
+
|
1272
|
+
return false
|
1273
|
+
end
|
1274
|
+
|
1275
|
+
###############################################################################
|
1276
|
+
# cloneEvent -- Method
|
1277
|
+
# This method does a deep clone of events Arrays in Ruby are objects and
|
1278
|
+
# we ocassionally need to preserve the state of the arrays.
|
1279
|
+
#
|
1280
|
+
# Params:
|
1281
|
+
# event: ???
|
1282
|
+
#
|
1283
|
+
# Results:
|
1284
|
+
# returns the event data after it as been marshaled into a byte stream.
|
1285
|
+
#
|
1286
|
+
###############################################################################
|
1287
|
+
def cloneEvent(event)
|
1288
|
+
return Marshal.load(Marshal.dump(event))
|
1289
|
+
end
|
1290
|
+
|
1291
|
+
###############################################################################
|
1292
|
+
# FlavorMatch -- Method
|
1293
|
+
# This method checks that all the test requirements meet the current
|
1294
|
+
# testing env.
|
1295
|
+
#
|
1296
|
+
# Params:
|
1297
|
+
# events: The soda events array.
|
1298
|
+
#
|
1299
|
+
# Results:
|
1300
|
+
# returns true if this test can be ran, else false. Will also return true
|
1301
|
+
# if the test has no requires info at all, but a warning message will be
|
1302
|
+
# logged.
|
1303
|
+
#
|
1304
|
+
###############################################################################
|
1305
|
+
def FlavorMatch(flavor)
|
1306
|
+
match = false
|
1307
|
+
flavor = flavor.downcase()
|
1308
|
+
|
1309
|
+
if (flavor =~ /,/)
|
1310
|
+
flavors = flavor.split(",")
|
1311
|
+
flavors.each do |sugflav|
|
1312
|
+
if (sugflav == @sugarFlavor)
|
1313
|
+
match = true
|
1314
|
+
break
|
1315
|
+
end
|
1316
|
+
end
|
1317
|
+
else
|
1318
|
+
if (flavor == @sugarFlavor)
|
1319
|
+
match = true
|
1320
|
+
end
|
1321
|
+
end
|
1322
|
+
|
1323
|
+
return match
|
1324
|
+
end
|
1325
|
+
|
1326
|
+
###############################################################################
|
1327
|
+
# CloseBrowser -- Method
|
1328
|
+
# This method closes browsers.
|
1329
|
+
#
|
1330
|
+
# Params:
|
1331
|
+
# None.
|
1332
|
+
#
|
1333
|
+
# Results:
|
1334
|
+
# None.
|
1335
|
+
#
|
1336
|
+
###############################################################################
|
1337
|
+
def CloseBrowser()
|
1338
|
+
result = 0
|
1339
|
+
|
1340
|
+
if (Watir::Browser.default =~ /firefox/i)
|
1341
|
+
result = SodaFireFox.CloseBrowser(@browser)
|
1342
|
+
else
|
1343
|
+
@browser.close()
|
1344
|
+
result = 1
|
1345
|
+
end
|
1346
|
+
|
1347
|
+
if (result < 1)
|
1348
|
+
@rep.ReportFailure("Failed trying to close browser: '#{result}'!\n")
|
1349
|
+
end
|
1350
|
+
end
|
1351
|
+
|
1352
|
+
###############################################################################
|
1353
|
+
# eventBrowser -- Method
|
1354
|
+
# This method handles all Soda browser events.
|
1355
|
+
#
|
1356
|
+
# Params:
|
1357
|
+
# event: This is the event to handle.
|
1358
|
+
#
|
1359
|
+
# Results:
|
1360
|
+
# returns a hash with keys: browser_close & error.
|
1361
|
+
#
|
1362
|
+
###############################################################################
|
1363
|
+
def eventBrowser(event)
|
1364
|
+
result = {
|
1365
|
+
'browser_closed' => false,
|
1366
|
+
'error' => 0
|
1367
|
+
}
|
1368
|
+
|
1369
|
+
event = SodaUtils.ConvertOldBrowserClose(event, @rep, @currentTestFile)
|
1370
|
+
|
1371
|
+
if (event.key?('action'))
|
1372
|
+
action = replaceVars(event['action'])
|
1373
|
+
@rep.log("Firing browser action: \"#{action}\"\n")
|
1374
|
+
|
1375
|
+
case action
|
1376
|
+
when "back"
|
1377
|
+
@browser.back
|
1378
|
+
when "forward"
|
1379
|
+
@browser.forward
|
1380
|
+
when "close"
|
1381
|
+
if (@browser != nil)
|
1382
|
+
CloseBrowser()
|
1383
|
+
result['browser_closed'] = true
|
1384
|
+
else
|
1385
|
+
PrintDebug("For some reason I got a nill @browser object!",
|
1386
|
+
SodaUtils::WARN)
|
1387
|
+
result['browser_closed'] = true
|
1388
|
+
end
|
1389
|
+
when "refresh"
|
1390
|
+
@browser.refresh
|
1391
|
+
else
|
1392
|
+
@rep.ReportFailure("Unknown browser action:"+
|
1393
|
+
" \"#{action}\".\n")
|
1394
|
+
result['error'] = -1
|
1395
|
+
end
|
1396
|
+
end
|
1397
|
+
|
1398
|
+
if (event.key?('url'))
|
1399
|
+
event['url'] = replaceVars(event['url'])
|
1400
|
+
@browser.goto(event['url'])
|
1401
|
+
@browser.wait()
|
1402
|
+
if (event['assertPage'] == nil || event['assertPage'] != "false")
|
1403
|
+
assertPage()
|
1404
|
+
end
|
1405
|
+
end
|
1406
|
+
|
1407
|
+
if (event.key?('assert'))
|
1408
|
+
PrintDebug("Asserting Browser Contains: #{event['assert']}\n");
|
1409
|
+
result['error'] = kindsOfBrowserAssert(event)
|
1410
|
+
end
|
1411
|
+
|
1412
|
+
if (event.key?('assertnot'))
|
1413
|
+
@rep.log("Asserting browser does not Contain: " +
|
1414
|
+
" #{event['assertnot']}\n");
|
1415
|
+
event['assert'] = event['assertnot'] # hack #
|
1416
|
+
result['error'] = kindsOfBrowserAssert(event, false)
|
1417
|
+
event.delete('assert') # clean up hack #
|
1418
|
+
end
|
1419
|
+
|
1420
|
+
if event.key?('send_keys')
|
1421
|
+
if ($win_only == true)
|
1422
|
+
case event['send_keys']
|
1423
|
+
when 'Ctrl+W'
|
1424
|
+
send_keys("^{w}")
|
1425
|
+
when 'BACKSPACE'
|
1426
|
+
send_keys("{BACKSPACE}")
|
1427
|
+
when 'ENTER'
|
1428
|
+
send_keys("{ENTER}")
|
1429
|
+
else
|
1430
|
+
send_keys(event['send_keys'])
|
1431
|
+
#@rep.log("eventBrowser: Unknown send_key: " +
|
1432
|
+
# "\"#{event['send_keys']}.\n", SodaUtils::WARN)
|
1433
|
+
end
|
1434
|
+
else
|
1435
|
+
msg = "Failed: This method Windows support only!\n"
|
1436
|
+
@rep.ReportFailure(msg)
|
1437
|
+
result['error'] = -1
|
1438
|
+
end
|
1439
|
+
end
|
1440
|
+
|
1441
|
+
return result
|
1442
|
+
end
|
1443
|
+
|
1444
|
+
###############################################################################
|
1445
|
+
# eventCSV -- Method
|
1446
|
+
# This method handles the csv file events.
|
1447
|
+
#
|
1448
|
+
# Params:
|
1449
|
+
# event: This is the event to handle.
|
1450
|
+
#
|
1451
|
+
# Results:
|
1452
|
+
# None.
|
1453
|
+
#
|
1454
|
+
###############################################################################
|
1455
|
+
def eventCSV(event)
|
1456
|
+
|
1457
|
+
event['file'] = replaceVars(event['file'])
|
1458
|
+
getRightCSV(event)
|
1459
|
+
csv = SodaCSV.new(event['file'])
|
1460
|
+
|
1461
|
+
while (record = csv.nextRecord())
|
1462
|
+
setScriptVar(event['var'], record)
|
1463
|
+
|
1464
|
+
if (event.key?('children'))
|
1465
|
+
handleEvents(cloneEvent(event['children']))
|
1466
|
+
end
|
1467
|
+
end
|
1468
|
+
end
|
1469
|
+
|
1470
|
+
###############################################################################
|
1471
|
+
# eventAttach - Method
|
1472
|
+
# This method attaches to a new browser window and then preforms the
|
1473
|
+
# all child in the new window.
|
1474
|
+
#
|
1475
|
+
# Params:
|
1476
|
+
# event: This is the soda <attach> event.
|
1477
|
+
#
|
1478
|
+
# Results:
|
1479
|
+
# None.
|
1480
|
+
#
|
1481
|
+
###############################################################################
|
1482
|
+
def eventAttach(event)
|
1483
|
+
title = nil
|
1484
|
+
url = nil
|
1485
|
+
new_browser = nil
|
1486
|
+
old_browser = @browser
|
1487
|
+
|
1488
|
+
PrintDebug("eventAttach: Starting.\n")
|
1489
|
+
|
1490
|
+
begin
|
1491
|
+
if (event.key?('title'))
|
1492
|
+
title = replaceVars(event['title'])
|
1493
|
+
title = stringToRegex(title)
|
1494
|
+
new_browser = @browser.attach(:title, title)
|
1495
|
+
elsif (event.key?('url'))
|
1496
|
+
url = replaceVars(event['url'])
|
1497
|
+
url = stringToRegex(url)
|
1498
|
+
new_browser = @browser.attach(:url, url)
|
1499
|
+
end
|
1500
|
+
rescue Exception=>e
|
1501
|
+
@rep.ReportException(e, true, false,
|
1502
|
+
"Failed trying to attach to browser window!");
|
1503
|
+
|
1504
|
+
e_dump = SodaUtils.DumpEvent(event)
|
1505
|
+
@rep.log("Event Dump From Exception: #{e_dump}!\n",
|
1506
|
+
SodaUtils::EVENT)
|
1507
|
+
|
1508
|
+
new_browser = nil
|
1509
|
+
end
|
1510
|
+
|
1511
|
+
if (new_browser != nil)
|
1512
|
+
@browser = new_browser
|
1513
|
+
if (event.key?('children'))
|
1514
|
+
handleEvents(cloneEvent(event['children']))
|
1515
|
+
end
|
1516
|
+
|
1517
|
+
@browser = old_browser
|
1518
|
+
end
|
1519
|
+
|
1520
|
+
PrintDebug("eventAttach: Finished.\n")
|
1521
|
+
end
|
1522
|
+
|
1523
|
+
###############################################################################
|
1524
|
+
# eventRequires -- Method
|
1525
|
+
# This method handles the requires events.
|
1526
|
+
#
|
1527
|
+
# Params:
|
1528
|
+
# event: This is the event to handle.
|
1529
|
+
#
|
1530
|
+
# Results:
|
1531
|
+
# None.
|
1532
|
+
#
|
1533
|
+
###############################################################################
|
1534
|
+
def eventRequires(event)
|
1535
|
+
flav = nil
|
1536
|
+
|
1537
|
+
flav = replaceVars(event['sugarflavor'])
|
1538
|
+
PrintDebug("Flavor: #{flav}\n")
|
1539
|
+
|
1540
|
+
if (FlavorMatch(flav) == true)
|
1541
|
+
if (event.key?('children'))
|
1542
|
+
handleEvents(cloneEvent(event['children']))
|
1543
|
+
else
|
1544
|
+
@rep.log("Found requires event without any children!\n",
|
1545
|
+
SodaUtils::WARN)
|
1546
|
+
end
|
1547
|
+
end
|
1548
|
+
end
|
1549
|
+
|
1550
|
+
def eventCondition(event)
|
1551
|
+
|
1552
|
+
end
|
1553
|
+
|
1554
|
+
###############################################################################
|
1555
|
+
# eventWhiteList -- Method
|
1556
|
+
# This method handles the whitelist soda event, by adding or deleting a
|
1557
|
+
# item to the whitelist at runtime.
|
1558
|
+
#
|
1559
|
+
# Input:
|
1560
|
+
# event: A soda whitelist event.
|
1561
|
+
#
|
1562
|
+
# Output:
|
1563
|
+
# None.
|
1564
|
+
#
|
1565
|
+
###############################################################################
|
1566
|
+
def eventWhiteList(event)
|
1567
|
+
err = 0
|
1568
|
+
|
1569
|
+
if (!event.key?('name'))
|
1570
|
+
@rep.ReportFailure("Missing 'name' attribute for whitelist tag!"+
|
1571
|
+
" Line number: #{event['line_number']}!\n")
|
1572
|
+
err = -1
|
1573
|
+
elsif (!event.key?('action'))
|
1574
|
+
@rep.ReportFailure("Missing 'action' attribute for whitelist tag!"+
|
1575
|
+
" Line number: #{event['line_number']}!\n")
|
1576
|
+
err = -1
|
1577
|
+
elsif (!event.key?('content') && event['action'] =~ /add/i)
|
1578
|
+
@rep.ReportFailure("Missing 'content' for whitelist tag!"+
|
1579
|
+
" Line number: #{event['line_number']}!\n")
|
1580
|
+
err = -1
|
1581
|
+
end
|
1582
|
+
|
1583
|
+
return if (err != 0)
|
1584
|
+
|
1585
|
+
case (event['action'])
|
1586
|
+
when /add/i
|
1587
|
+
found_key = false
|
1588
|
+
|
1589
|
+
@whiteList.each do |hash|
|
1590
|
+
next if (!hash.key?(event['name']))
|
1591
|
+
if (hash.key?(event['name']))
|
1592
|
+
found_key = true
|
1593
|
+
break
|
1594
|
+
end
|
1595
|
+
end
|
1596
|
+
|
1597
|
+
if (found_key)
|
1598
|
+
@rep.ReportFailure("Trying to add whitelist that already"+
|
1599
|
+
" exists: '#{event['name']}'!\n")
|
1600
|
+
else
|
1601
|
+
new_white = {
|
1602
|
+
'name' => event['name'],
|
1603
|
+
'data' => event['content']
|
1604
|
+
}
|
1605
|
+
|
1606
|
+
@whiteList.push(new_white)
|
1607
|
+
@rep.log("Adding data to whitelist: '#{new_white['name']}'.\n")
|
1608
|
+
end
|
1609
|
+
when /delete/i
|
1610
|
+
index = -1
|
1611
|
+
found_key = false
|
1612
|
+
|
1613
|
+
@whiteList.each do |hash|
|
1614
|
+
index += 1
|
1615
|
+
next if (!hash.key?('name'))
|
1616
|
+
if (hash['name'] == event['name'])
|
1617
|
+
found_key = true
|
1618
|
+
break
|
1619
|
+
end
|
1620
|
+
end
|
1621
|
+
|
1622
|
+
if (found_key)
|
1623
|
+
@whiteList.delete_at(index)
|
1624
|
+
else
|
1625
|
+
@rep.ReportFailure("Failed to find whitelist name: "+
|
1626
|
+
"'#{event['name']}'!\n")
|
1627
|
+
end
|
1628
|
+
end
|
1629
|
+
end
|
1630
|
+
|
1631
|
+
###############################################################################
|
1632
|
+
###############################################################################
|
1633
|
+
def eventRuby(event)
|
1634
|
+
result = 0
|
1635
|
+
|
1636
|
+
if (event['content'].empty?)
|
1637
|
+
return 0
|
1638
|
+
end
|
1639
|
+
|
1640
|
+
eresult = eval(event['content'])
|
1641
|
+
eresult = "#{eresult}"
|
1642
|
+
|
1643
|
+
if (eresult != event['assert'])
|
1644
|
+
result = false
|
1645
|
+
else
|
1646
|
+
result = true
|
1647
|
+
end
|
1648
|
+
|
1649
|
+
@rep.Assert(result, "Evaling ruby code results: Expecting:"+
|
1650
|
+
" \"#{event['assert']}\" found: \"#{eresult}\".\n",
|
1651
|
+
@currentTestFile, "#{event['line_number']}")
|
1652
|
+
|
1653
|
+
end
|
1654
|
+
|
1655
|
+
###############################################################################
|
1656
|
+
# eventScript -- Method
|
1657
|
+
# This method handles all script events.
|
1658
|
+
#
|
1659
|
+
# Params:
|
1660
|
+
# event: This is the event to handle.
|
1661
|
+
#
|
1662
|
+
# Results:
|
1663
|
+
# None.
|
1664
|
+
#
|
1665
|
+
###############################################################################
|
1666
|
+
def eventScript(event)
|
1667
|
+
|
1668
|
+
if (event.key?('file'))
|
1669
|
+
# specified a new csv to file
|
1670
|
+
if (event.key?('csv'))
|
1671
|
+
event['csv'] = replaceVars(event['csv'])
|
1672
|
+
@newCSV.push({"#{event['file']}"=>"#{event['csv']}"})
|
1673
|
+
end
|
1674
|
+
|
1675
|
+
event['file'] = replaceVars(event['file'])
|
1676
|
+
@fileStack.push(event['file'])
|
1677
|
+
script = getScript(event['file'])
|
1678
|
+
if (script != nil)
|
1679
|
+
parent_script = @currentTestFile
|
1680
|
+
@currentTestFile = event['file']
|
1681
|
+
handleEvents(script)
|
1682
|
+
@currentTestFile = parent_script
|
1683
|
+
else
|
1684
|
+
msg = "Failed opening script file: \"#{event['file']}\"!\n"
|
1685
|
+
@rep.ReportFailure(msg)
|
1686
|
+
end
|
1687
|
+
|
1688
|
+
@fileStack.pop()
|
1689
|
+
end
|
1690
|
+
|
1691
|
+
if (event.key?('fileset'))
|
1692
|
+
event['fileset'] = replaceVars(event['fileset'])
|
1693
|
+
@rep.log("Starting New Soda Fileset: #{event['fileset']}\n")
|
1694
|
+
getDirScript(event['fileset'])
|
1695
|
+
@rep.log("Fileset: #{event['fileset']} finished.\n")
|
1696
|
+
end
|
1697
|
+
end
|
1698
|
+
|
1699
|
+
###############################################################################
|
1700
|
+
# CheckJavaScriptErrors -- Method
|
1701
|
+
# This function checks the current page for all javascript errors.
|
1702
|
+
#
|
1703
|
+
# Params:
|
1704
|
+
# None.
|
1705
|
+
#
|
1706
|
+
# Results:
|
1707
|
+
# Always returns 0.
|
1708
|
+
#
|
1709
|
+
###############################################################################
|
1710
|
+
def CheckJavaScriptErrors()
|
1711
|
+
result = nil
|
1712
|
+
data = nil
|
1713
|
+
|
1714
|
+
if (Watir::Browser.default == "firefox")
|
1715
|
+
result = @browser.execute_script(
|
1716
|
+
"#{SodaUtils::FIREFOX_JS_ERROR_CHECK_SRC}")
|
1717
|
+
data = result.split(/######/)
|
1718
|
+
data.each do |line|
|
1719
|
+
if ( (line != "") &&
|
1720
|
+
(line !~ /chrome:\/\/browser\/content\/tabbrowser\.xm/) &&
|
1721
|
+
(line !~ /SShStarter.js/i ))
|
1722
|
+
@rep.ReportJavaScriptError("Javascript Error:#{line}\n",
|
1723
|
+
$skip_css_errors)
|
1724
|
+
|
1725
|
+
end
|
1726
|
+
end
|
1727
|
+
end
|
1728
|
+
|
1729
|
+
return 0
|
1730
|
+
end
|
1731
|
+
|
1732
|
+
###############################################################################
|
1733
|
+
# eventJavascript -- Method
|
1734
|
+
# This method handles all script events.
|
1735
|
+
#
|
1736
|
+
# Params:
|
1737
|
+
# event: This is the event to handle.
|
1738
|
+
#
|
1739
|
+
# Results:
|
1740
|
+
# None.
|
1741
|
+
#
|
1742
|
+
###############################################################################
|
1743
|
+
def eventJavascript(event)
|
1744
|
+
result = nil
|
1745
|
+
|
1746
|
+
if (event['content'].length > 0)
|
1747
|
+
if (Watir::Browser.default == 'firefox')
|
1748
|
+
# Executing javascript from within the firefox window context
|
1749
|
+
# (injection) requires firebug, for now.
|
1750
|
+
toExec = "";
|
1751
|
+
if (event.key?('addUtils') && (getStringBool(event['addUtils'])))
|
1752
|
+
event['content'] = SodaUtils::getSodaJS() + event['content'];
|
1753
|
+
end
|
1754
|
+
|
1755
|
+
escapedContent = event['content'].gsub(/\\/, '\\').gsub(/"/, '\"');
|
1756
|
+
|
1757
|
+
toExec = <<JSCode
|
1758
|
+
if (typeof window.Firebug != "undefined") {
|
1759
|
+
window.TabWatcher.watchBrowser(window.FirebugChrome.getCurrentBrowser());
|
1760
|
+
window.Firebug.minimizeBar();
|
1761
|
+
window.Firebug.CommandLine.evaluateInWebPage("#{escapedContent}", browser.contentDocument.defaultView);
|
1762
|
+
window.Firebug.closeFirebug();
|
1763
|
+
}
|
1764
|
+
JSCode
|
1765
|
+
|
1766
|
+
result = @browser.execute_script(toExec)
|
1767
|
+
else
|
1768
|
+
escapedContent = event['content'].gsub(/\\/, '\\').gsub(/"/, '\"')
|
1769
|
+
toExec = 'browser.document.parentWindow.execScript("' + escapedContent + '")'
|
1770
|
+
result = @browser.execute_script(event['content'])
|
1771
|
+
end
|
1772
|
+
result = result.to_s()
|
1773
|
+
PrintDebug("JavaScript Results: \"#{result}\"\n")
|
1774
|
+
else
|
1775
|
+
@rep.log("No javascript source content found!", SodaUtils::ERROR)
|
1776
|
+
return -1
|
1777
|
+
end
|
1778
|
+
|
1779
|
+
CheckJavaScriptErrors()
|
1780
|
+
end
|
1781
|
+
|
1782
|
+
###############################################################################
|
1783
|
+
# eventLink -- Method
|
1784
|
+
# This method handles the Link event.
|
1785
|
+
#
|
1786
|
+
# Params:
|
1787
|
+
# event: This is the soda event to handle.
|
1788
|
+
#
|
1789
|
+
# Results:
|
1790
|
+
# None.
|
1791
|
+
#
|
1792
|
+
###############################################################################
|
1793
|
+
def eventLink(event)
|
1794
|
+
field = nil
|
1795
|
+
|
1796
|
+
field = getField(event)
|
1797
|
+
return field
|
1798
|
+
end
|
1799
|
+
|
1800
|
+
###############################################################################
|
1801
|
+
# eventWait -- Method
|
1802
|
+
#
|
1803
|
+
#
|
1804
|
+
# Results:
|
1805
|
+
# return true if a next should be called, else false.
|
1806
|
+
#
|
1807
|
+
#
|
1808
|
+
###############################################################################
|
1809
|
+
def eventWait(event)
|
1810
|
+
result = false
|
1811
|
+
|
1812
|
+
if ( event.key?('condition') &&
|
1813
|
+
getStringBool(event['condition']) &&
|
1814
|
+
event.key?('children') )
|
1815
|
+
|
1816
|
+
event['children'].each do |sub_event|
|
1817
|
+
@rep.log("Waiting Page Load: \n")
|
1818
|
+
waitByMultipleCondition(sub_event, event['timeout'])
|
1819
|
+
end
|
1820
|
+
|
1821
|
+
result = true
|
1822
|
+
elsif (event.key?('timeout'))
|
1823
|
+
@rep.log("Waiting Page Load: #{event['timeout']}s\n")
|
1824
|
+
sleep(Integer(event['timeout']))
|
1825
|
+
@rep.log("Page Load Finished.\n")
|
1826
|
+
result = true
|
1827
|
+
else
|
1828
|
+
@rep.log("Waiting Page Load: 10s\n")
|
1829
|
+
sleep(10)
|
1830
|
+
PrintDebug("Page Load Finished.\n")
|
1831
|
+
result = true
|
1832
|
+
end
|
1833
|
+
|
1834
|
+
return result
|
1835
|
+
end
|
1836
|
+
|
1837
|
+
###############################################################################
|
1838
|
+
# eventVar -- Method
|
1839
|
+
# This method handles the var event.
|
1840
|
+
#
|
1841
|
+
# Params:
|
1842
|
+
# event: This is the event to handle.
|
1843
|
+
#
|
1844
|
+
###############################################################################
|
1845
|
+
def eventVar(event)
|
1846
|
+
|
1847
|
+
if (event['set'] == '#stamp#')
|
1848
|
+
event['set'] = Soda.getStamp()
|
1849
|
+
end
|
1850
|
+
|
1851
|
+
if (event['set'] == '#rand#')
|
1852
|
+
event['set'] = rand(999999)
|
1853
|
+
end
|
1854
|
+
|
1855
|
+
setScriptVar(event['var'], event['set']);
|
1856
|
+
|
1857
|
+
end
|
1858
|
+
|
1859
|
+
###############################################################################
|
1860
|
+
# eventFileField -- Method:
|
1861
|
+
# This method handles the FileField event.
|
1862
|
+
#
|
1863
|
+
# Params:
|
1864
|
+
# event: THis is the soda event to handle.
|
1865
|
+
#
|
1866
|
+
# Results:
|
1867
|
+
# None.
|
1868
|
+
#
|
1869
|
+
###############################################################################
|
1870
|
+
def eventFileField(event)
|
1871
|
+
os = nil
|
1872
|
+
abs = nil
|
1873
|
+
upload_file = nil
|
1874
|
+
path = nil
|
1875
|
+
what = nil
|
1876
|
+
|
1877
|
+
event['do'] = 'file_field'
|
1878
|
+
if (event.key?('set'))
|
1879
|
+
upload_file = event['set']
|
1880
|
+
else
|
1881
|
+
@rep.Assert(false, "eventFileField: 'set' is empty!\n",
|
1882
|
+
@currentTestFile)
|
1883
|
+
return -1
|
1884
|
+
end
|
1885
|
+
|
1886
|
+
path = Pathname.new(upload_file)
|
1887
|
+
|
1888
|
+
if (!path.absolute?)
|
1889
|
+
upload_file = "#{$SodaHome}/#{upload_file}"
|
1890
|
+
end
|
1891
|
+
|
1892
|
+
os = SodaUtils.GetOsType
|
1893
|
+
if (os =~ /windows/i)
|
1894
|
+
upload_file = upload_file.gsub("/", "\\")
|
1895
|
+
end
|
1896
|
+
|
1897
|
+
PrintDebug("Uploading file: \"#{upload_file}\"\n")
|
1898
|
+
|
1899
|
+
if (event.key?("id"))
|
1900
|
+
what = replaceVars(event['id'])
|
1901
|
+
@browser.file_field(:id, "#{what}").set(upload_file)
|
1902
|
+
elsif (event.key?("value"))
|
1903
|
+
what = replaceVars(event['value'])
|
1904
|
+
@browser.file_field(:value, "#{what}").set(upload_file)
|
1905
|
+
elsif (event.key?("name"))
|
1906
|
+
what = replaceVars(event['name'])
|
1907
|
+
@browser.file_field(:name, "#{what}").set(upload_file)
|
1908
|
+
else
|
1909
|
+
@rep.log("Unable to find control accessor for FileField!\n",
|
1910
|
+
SodaUtils::ERROR)
|
1911
|
+
end
|
1912
|
+
end
|
1913
|
+
|
1914
|
+
###############################################################################
|
1915
|
+
# eventPuts -- Method
|
1916
|
+
# This method handles the puts event.
|
1917
|
+
#
|
1918
|
+
# Params:
|
1919
|
+
# event: The soda puts event.
|
1920
|
+
#
|
1921
|
+
# Results:
|
1922
|
+
# None.
|
1923
|
+
#
|
1924
|
+
###############################################################################
|
1925
|
+
def eventPuts(event)
|
1926
|
+
if (event.key?('text'))
|
1927
|
+
temp = replaceVars(event['text'])
|
1928
|
+
@rep.log("#{temp}\n" )
|
1929
|
+
elsif (event.key?('var'))
|
1930
|
+
var = replaceVars(event['var'])
|
1931
|
+
@rep.log("#{var}\n")
|
1932
|
+
end
|
1933
|
+
end
|
1934
|
+
|
1935
|
+
###############################################################################
|
1936
|
+
# eventMouseClick -- Method
|
1937
|
+
# This method handles soda mouseclick events. Currently this is only
|
1938
|
+
# supported on windows.
|
1939
|
+
#
|
1940
|
+
# Params:
|
1941
|
+
# event: This is the soda event to handle.
|
1942
|
+
#
|
1943
|
+
# Results:
|
1944
|
+
# None.
|
1945
|
+
#
|
1946
|
+
###############################################################################
|
1947
|
+
def eventMouseClick(event)
|
1948
|
+
PrintDebug("eventMouseClick: Starting.\n")
|
1949
|
+
if ($win_only == true)
|
1950
|
+
if (event.key?('xpos') && event.key?('ypos'))
|
1951
|
+
MouseClick(event['xpos'],event['ypos']);
|
1952
|
+
end
|
1953
|
+
else
|
1954
|
+
msg = "eventMouseClick Failed: This method Windows support only!\n"
|
1955
|
+
@rep.ReportFailure(msg)
|
1956
|
+
end
|
1957
|
+
|
1958
|
+
PrintDebug("eventMouseClick: Finished.\n")
|
1959
|
+
end
|
1960
|
+
|
1961
|
+
###############################################################################
|
1962
|
+
# eventFieldAction -- Method
|
1963
|
+
#
|
1964
|
+
#
|
1965
|
+
#
|
1966
|
+
###############################################################################
|
1967
|
+
def eventFieldAction(event, fieldType)
|
1968
|
+
js = nil
|
1969
|
+
result = nil
|
1970
|
+
foundaction = nil
|
1971
|
+
foundvalue = nil
|
1972
|
+
fieldactions = [
|
1973
|
+
'clear',
|
1974
|
+
'focus',
|
1975
|
+
'click',
|
1976
|
+
'set',
|
1977
|
+
'assert',
|
1978
|
+
'assertnot',
|
1979
|
+
'include',
|
1980
|
+
'noninclude',
|
1981
|
+
'var',
|
1982
|
+
'vartext',
|
1983
|
+
'children',
|
1984
|
+
'button',
|
1985
|
+
'exists',
|
1986
|
+
'link',
|
1987
|
+
'append',
|
1988
|
+
'disabled']
|
1989
|
+
|
1990
|
+
if (@SIGNAL_STOP != false)
|
1991
|
+
exit(-1)
|
1992
|
+
end
|
1993
|
+
|
1994
|
+
fieldactions.each do |action|
|
1995
|
+
if (event.key?(action))
|
1996
|
+
foundaction = action
|
1997
|
+
break
|
1998
|
+
end
|
1999
|
+
end
|
2000
|
+
|
2001
|
+
if (foundaction == nil)
|
2002
|
+
foundaction = event['do']
|
2003
|
+
end
|
2004
|
+
|
2005
|
+
if (event.key?("alert") )
|
2006
|
+
if (event['alert'] =~ /true/i)
|
2007
|
+
@rep.log("Enabling Alert Hack\n")
|
2008
|
+
fieldType.alertHack(true, true)
|
2009
|
+
else
|
2010
|
+
fieldType.alertHack(false, false)
|
2011
|
+
@rep.log("Disabeling alert!\n")
|
2012
|
+
PrintDebug("eventFieldAction: Finished.\n")
|
2013
|
+
return
|
2014
|
+
end
|
2015
|
+
end
|
2016
|
+
|
2017
|
+
if (event.key?("jscriptevent"))
|
2018
|
+
js = replaceVars(event['jscriptevent'])
|
2019
|
+
end
|
2020
|
+
|
2021
|
+
case foundaction
|
2022
|
+
when "append"
|
2023
|
+
result = fieldType.append(@curEl, replaceVars(event['append']))
|
2024
|
+
if (result != 0)
|
2025
|
+
event['current_test_file'] = @currentTestFile
|
2026
|
+
e_dump = SodaUtils.DumpEvent(event)
|
2027
|
+
@rep.log("Event Dump: #{e_dump}\n", SodaUtils::EVENT)
|
2028
|
+
end
|
2029
|
+
when "button"
|
2030
|
+
fieldType.click(@curEl, @SugarWait)
|
2031
|
+
@browser.wait()
|
2032
|
+
if (event['assertPage'] == nil || event['assertPage'] != "false")
|
2033
|
+
assertPage()
|
2034
|
+
end
|
2035
|
+
when "link"
|
2036
|
+
if ( (js != nil) && (js =~ /onmouseover/i) )
|
2037
|
+
jswait = true
|
2038
|
+
if (event.key?('jswait'))
|
2039
|
+
jswait = false if (event['jswait'] =~ /false/i)
|
2040
|
+
end
|
2041
|
+
fieldType.jsevent(@curEl, js, jswait)
|
2042
|
+
end
|
2043
|
+
fieldType.click(@curEl, @SugarWait)
|
2044
|
+
@browser.wait()
|
2045
|
+
if (event['assertPage'] == nil || event['assertPage'] != "false")
|
2046
|
+
assertPage()
|
2047
|
+
end
|
2048
|
+
when "clear"
|
2049
|
+
if(event['clear'])
|
2050
|
+
event['clear'] = replaceVars(event['clear'])
|
2051
|
+
case event['clear']
|
2052
|
+
when /true/i
|
2053
|
+
PrintDebug("Clearing field\n")
|
2054
|
+
fieldType.clear(@curEl)
|
2055
|
+
when /false/i
|
2056
|
+
PrintDebug("Skipping field clearing event as its value" +
|
2057
|
+
" was: \"#{event['clear']}\".\n")
|
2058
|
+
else
|
2059
|
+
@rep.log("Found unsupported value for <textfield clear" +
|
2060
|
+
"=\"true/false\" />!\n", SodaUtils::WARN)
|
2061
|
+
@rep.log("Unsupported clear value =>" +
|
2062
|
+
" \"#{event['clear']}\".\n", SodaUtils::WARN)
|
2063
|
+
end
|
2064
|
+
end
|
2065
|
+
when "focus"
|
2066
|
+
if (event['focus'])
|
2067
|
+
PrintDebug("Setting focus\n")
|
2068
|
+
fieldType.focus(@curEl)
|
2069
|
+
end
|
2070
|
+
when "radio"
|
2071
|
+
if (!fieldType.getStringTrue(event['set']) &&
|
2072
|
+
@autoClick[event['do']])
|
2073
|
+
fieldType.click(@curEl, @SugarWait)
|
2074
|
+
@browser.wait()
|
2075
|
+
end
|
2076
|
+
when "click"
|
2077
|
+
if ( (fieldType.getStringTrue(event['click'])) ||
|
2078
|
+
(!event.key?('click') && @autoClick[event['do']]) )
|
2079
|
+
|
2080
|
+
PrintDebug("Performing click\n")
|
2081
|
+
fieldType.click(@curEl, @SugarWait)
|
2082
|
+
@browser.wait()
|
2083
|
+
if (event['assertPage'] == nil || event['assertPage'] != "false")
|
2084
|
+
assertPage()
|
2085
|
+
end
|
2086
|
+
end
|
2087
|
+
when "set"
|
2088
|
+
PrintDebug("Setting value to #{event['set']}\n")
|
2089
|
+
result = fieldType.set(@curEl, event['set'])
|
2090
|
+
if (result != 0)
|
2091
|
+
event['current_test_file'] = @currentTestFile
|
2092
|
+
e_dump = SodaUtils.DumpEvent(event)
|
2093
|
+
@rep.log("Event Dump: #{e_dump}\n", SodaUtils::EVENT)
|
2094
|
+
end
|
2095
|
+
when "assert"
|
2096
|
+
fieldEventAssert(event, fieldType)
|
2097
|
+
when "assertnot"
|
2098
|
+
fieldEventAssert(event, fieldType)
|
2099
|
+
when "include"
|
2100
|
+
event['include'] = stringToRegex(event['include'])
|
2101
|
+
event['include'] = replaceVars(event['include'])
|
2102
|
+
@rep.log("Asserting Exist Option: #{event['include']}\n")
|
2103
|
+
@contents = SodaSelectField.getAllContents(@curEl)
|
2104
|
+
@rep.Assert(checkSelectList(@contents, event['include']),
|
2105
|
+
@currentTestFile)
|
2106
|
+
when "noninclude"
|
2107
|
+
event['noninclude'] = stringToRegex(event['noninclude'])
|
2108
|
+
event['noninclude'] = replaceVars(event['noninclude'])
|
2109
|
+
@rep.log("Asserting Not Exist Option: " +
|
2110
|
+
"#{event['noninclude']}", SodaUtils::ERROR)
|
2111
|
+
@contents = SodaSelectField.getAllContents(@curEl)
|
2112
|
+
@rep.Assert(!(checkSelectList(@contents, event['noninclude'])),
|
2113
|
+
@currentTestFile)
|
2114
|
+
when "var"
|
2115
|
+
setScriptVar(event['var'], fieldType.getValue(@curEl))
|
2116
|
+
when "vartext"
|
2117
|
+
setScriptVar(event['vartext'], fieldType.getText(@curEl))
|
2118
|
+
when "children"
|
2119
|
+
@parentEl.push(@curEl)
|
2120
|
+
handleEvents(event['children'])
|
2121
|
+
@parentEl.pop()
|
2122
|
+
when "disabled"
|
2123
|
+
event['disabled'] = getStringBool(event['disabled'])
|
2124
|
+
FieldUtils.CheckDisabled(@curEl, event['disabled'], @rep)
|
2125
|
+
when "exists"
|
2126
|
+
# do nothing #
|
2127
|
+
else
|
2128
|
+
msg = "Failed to find supported field action.\n"
|
2129
|
+
@rep.log(msg, SodaUtils::WARN)
|
2130
|
+
e_dump = SodaUtils.DumpEvent(event)
|
2131
|
+
@rep.log("Event Dump: #{e_dump}\n", SodaUtils::EVENT)
|
2132
|
+
end
|
2133
|
+
end
|
2134
|
+
|
2135
|
+
###############################################################################
|
2136
|
+
# fieldEventAssert -- Method
|
2137
|
+
# This method handles the field action 'assert'.
|
2138
|
+
#
|
2139
|
+
# Params:
|
2140
|
+
# event: The soda event with the field action 'assert'.
|
2141
|
+
#
|
2142
|
+
# Results:
|
2143
|
+
# None.
|
2144
|
+
#
|
2145
|
+
###############################################################################
|
2146
|
+
def fieldEventAssert(event, fieldType)
|
2147
|
+
msg = ""
|
2148
|
+
assert_type = ""
|
2149
|
+
result = 0
|
2150
|
+
|
2151
|
+
if (event.key?('assertnot'))
|
2152
|
+
assert_type = 'assertnot'
|
2153
|
+
else
|
2154
|
+
assert_type = event['assert']
|
2155
|
+
end
|
2156
|
+
|
2157
|
+
case assert_type
|
2158
|
+
when /assertnot/i
|
2159
|
+
contains = replaceVars(event['assertnot'] )
|
2160
|
+
msg = "Asserting that value doesn't exist: \"#{contains}\""
|
2161
|
+
@rep.log("#{msg}\n")
|
2162
|
+
result = @rep.Assert(!(fieldType.assert(@curEl, contains)), msg,
|
2163
|
+
@currentTestFile, "#{event['line_number']}")
|
2164
|
+
when /enabled/i
|
2165
|
+
msg = "Asserting that Element is enabled."
|
2166
|
+
@rep.log("#{msg}\n")
|
2167
|
+
result = @rep.Assert(fieldType.enabled(@curEl), msg,
|
2168
|
+
@currentTestFile, "#{event['line_number']}")
|
2169
|
+
when /disabled/i
|
2170
|
+
msg = "Asserting that Element is disabled."
|
2171
|
+
@rep.log("#{msg}\n")
|
2172
|
+
result = @rep.Assert(fieldType.disabled(@curEl), msg,
|
2173
|
+
@currentTestFile, "#{event['line_number']}")
|
2174
|
+
else
|
2175
|
+
contains = replaceVars(event['assert'])
|
2176
|
+
@rep.log("Asserting value: #{contains}\n")
|
2177
|
+
msg = "Asserting that value: \"#{contains}\" exists."
|
2178
|
+
result = @rep.Assert(fieldType.assert(@curEl, contains), msg,
|
2179
|
+
@currentTestFile, "#{event['line_number']}")
|
2180
|
+
end
|
2181
|
+
|
2182
|
+
if (result != 0)
|
2183
|
+
@FAILEDTESTS.push(@currentTestFile)
|
2184
|
+
end
|
2185
|
+
|
2186
|
+
end
|
2187
|
+
|
2188
|
+
###############################################################################
|
2189
|
+
# crazyEvilIETabHack -- Method
|
2190
|
+
# This method make ie's tab pages act like firefox's in the since that,
|
2191
|
+
# when a new tab is opened in ie and that new tab has focus watir doesn't
|
2192
|
+
# notice and keeps working on the browser tab that isn't in focus anymore.
|
2193
|
+
# Yes this is totally lame, but here is the hack to make it work.
|
2194
|
+
#
|
2195
|
+
# Note:
|
2196
|
+
# Because the window handle is the same for the tabbed window I really
|
2197
|
+
# didn't need to go through all of the trouble, I could have just
|
2198
|
+
# reattached to the same hwnd and this would have all worked, but then
|
2199
|
+
# this code would not be able to support when we are going to no be using
|
2200
|
+
# tab's. Really we should not be using tabs anymore anyway!
|
2201
|
+
#
|
2202
|
+
# Params:
|
2203
|
+
# None.
|
2204
|
+
#
|
2205
|
+
# Results:
|
2206
|
+
# Always returns 0.
|
2207
|
+
#
|
2208
|
+
###############################################################################
|
2209
|
+
def crazyEvilIETabHack()
|
2210
|
+
if(Watir::Browser.default !~ /ie/i)
|
2211
|
+
return 0
|
2212
|
+
end
|
2213
|
+
|
2214
|
+
if (@ieHwnd != 0)
|
2215
|
+
ie_count = 0
|
2216
|
+
|
2217
|
+
Watir::IE.each do |tab|
|
2218
|
+
ie_count += 1
|
2219
|
+
end
|
2220
|
+
|
2221
|
+
if ((ie_count == 1) && (@ieHwnd != 0))
|
2222
|
+
@browser = Watir::Browser.attach(:hwnd, @ieHwnd)
|
2223
|
+
PrintDebug("IE hack: switching back to parent window handle:" +
|
2224
|
+
" \"#{@ieHwnd}\".\n")
|
2225
|
+
@ieHwnd = 0
|
2226
|
+
end
|
2227
|
+
end
|
2228
|
+
|
2229
|
+
Watir::IE.each do |tab|
|
2230
|
+
url = tab.url
|
2231
|
+
if ( (url =~ /popup/i) && (@ieHwnd == 0))
|
2232
|
+
@ieHwnd = @browser.hwnd()
|
2233
|
+
@browser = Watir::Browser.attach(:hwnd, tab.hwnd)
|
2234
|
+
tmp_hwnd = @browser.hwnd()
|
2235
|
+
PrintDebug("IE hack: found popup window switching from parent"+
|
2236
|
+
" handle: \"#{@ieHwnd}\" to popup handle: \"#{tab.hwnd}\".\n")
|
2237
|
+
break
|
2238
|
+
end
|
2239
|
+
end
|
2240
|
+
|
2241
|
+
return 0
|
2242
|
+
end
|
2243
|
+
|
2244
|
+
###############################################################################
|
2245
|
+
# handleEvents -- Method
|
2246
|
+
# This is the heart of event handling used as a switch statement instand
|
2247
|
+
# of classes to keep it simple for QA to modify.
|
2248
|
+
#
|
2249
|
+
# Params:
|
2250
|
+
# events: The result of the getScript method, really all the xml events.
|
2251
|
+
#
|
2252
|
+
# Results:
|
2253
|
+
# A big flip'n sloppy mess!
|
2254
|
+
#
|
2255
|
+
# Notes:
|
2256
|
+
# Total hack! This needs to be redone from the ground up it is a total
|
2257
|
+
# sloppy mess!
|
2258
|
+
#
|
2259
|
+
###############################################################################
|
2260
|
+
def handleEvents(events)
|
2261
|
+
browser_closed = false
|
2262
|
+
result = 0
|
2263
|
+
jswait = true
|
2264
|
+
result = 0
|
2265
|
+
exception_event = nil
|
2266
|
+
|
2267
|
+
for next_event in events
|
2268
|
+
if (@exceptionExit != false)
|
2269
|
+
@rep.log("Exception occured, now exiting...\n")
|
2270
|
+
@exceptionExit = false
|
2271
|
+
return -1
|
2272
|
+
end
|
2273
|
+
|
2274
|
+
events = getEvents(next_event)
|
2275
|
+
|
2276
|
+
for event in events
|
2277
|
+
begin
|
2278
|
+
@rep.AddEventCount()
|
2279
|
+
@curEl = nil
|
2280
|
+
fieldType = nil
|
2281
|
+
|
2282
|
+
event = SodaUtils.ConvertOldAssert(event, @rep, @currentTestFile)
|
2283
|
+
|
2284
|
+
$mutex.synchronize {
|
2285
|
+
$global_time = Time.new()
|
2286
|
+
}
|
2287
|
+
|
2288
|
+
crazyEvilIETabHack()
|
2289
|
+
|
2290
|
+
if (event.key?('set') && event['set'].is_a?(String) &&
|
2291
|
+
event['set'].index('{@') != nil)
|
2292
|
+
|
2293
|
+
default = event.key?('default')?event['default']: ''
|
2294
|
+
var_temp = replaceVars(event['set'], default)
|
2295
|
+
|
2296
|
+
# if set nil to object, nothing to do just skip
|
2297
|
+
if (var_temp == nil)
|
2298
|
+
break
|
2299
|
+
end
|
2300
|
+
|
2301
|
+
event['set'] = var_temp
|
2302
|
+
end
|
2303
|
+
|
2304
|
+
if (event.key?('assert'))
|
2305
|
+
event['assert'] = replaceVars(event['assert'])
|
2306
|
+
event['assert'] = stringToRegex(event['assert'])
|
2307
|
+
elsif (event.key?('assertnot'))
|
2308
|
+
event['assertnot'] = replaceVars(event['assertnot'])
|
2309
|
+
event['assertnot'] = stringToRegex(event['assertnot'])
|
2310
|
+
end
|
2311
|
+
|
2312
|
+
case event['do']
|
2313
|
+
when "exception"
|
2314
|
+
PrintDebug("Found Exception Handler.\n")
|
2315
|
+
exception_event = event
|
2316
|
+
next
|
2317
|
+
when "breakexit"
|
2318
|
+
@breakExit = true
|
2319
|
+
next
|
2320
|
+
when "whitelist"
|
2321
|
+
eventWhiteList(event)
|
2322
|
+
next
|
2323
|
+
when "sugarwait"
|
2324
|
+
SodaUtils.WaitSugarAjaxDone(@browser, @rep)
|
2325
|
+
next
|
2326
|
+
when "condition"
|
2327
|
+
eventCondition(event)
|
2328
|
+
next
|
2329
|
+
when "ruby"
|
2330
|
+
eventRuby(event)
|
2331
|
+
next
|
2332
|
+
when "wait"
|
2333
|
+
if (eventWait(event) == true)
|
2334
|
+
next
|
2335
|
+
end
|
2336
|
+
when "browser"
|
2337
|
+
err = eventBrowser(event)
|
2338
|
+
if (err['error'] != 0)
|
2339
|
+
result = -1
|
2340
|
+
end
|
2341
|
+
|
2342
|
+
next
|
2343
|
+
when "requires"
|
2344
|
+
eventRequires(event)
|
2345
|
+
next
|
2346
|
+
when "attach"
|
2347
|
+
eventAttach(event)
|
2348
|
+
next
|
2349
|
+
when "csv"
|
2350
|
+
eventCSV(event)
|
2351
|
+
next
|
2352
|
+
when "comment"
|
2353
|
+
next
|
2354
|
+
when "timestamp"
|
2355
|
+
@vars['stamp'] = Time.now().strftime("%y%m%d_%H%M%S")
|
2356
|
+
next
|
2357
|
+
when "script"
|
2358
|
+
eventScript(event)
|
2359
|
+
next
|
2360
|
+
when "var"
|
2361
|
+
eventVar(event)
|
2362
|
+
next
|
2363
|
+
when "javascript"
|
2364
|
+
eventJavascript(event)
|
2365
|
+
next
|
2366
|
+
when "puts"
|
2367
|
+
eventPuts(event)
|
2368
|
+
next
|
2369
|
+
when "mouseclick"
|
2370
|
+
eventMouseClick(event)
|
2371
|
+
next
|
2372
|
+
when "filefield"
|
2373
|
+
fieldType = SodaFileField
|
2374
|
+
eventFileField(event)
|
2375
|
+
next
|
2376
|
+
when "textfield"
|
2377
|
+
fieldType = SodaField
|
2378
|
+
event['do'] = 'text_field'
|
2379
|
+
@curEl = getField(event)
|
2380
|
+
when "textarea"
|
2381
|
+
fieldType = SodaField
|
2382
|
+
event['do'] = 'text_field'
|
2383
|
+
@curEl = getField(event)
|
2384
|
+
when "checkbox"
|
2385
|
+
fieldType = SodaCheckBoxField
|
2386
|
+
event['do'] = 'checkbox'
|
2387
|
+
@curEl = getField(event)
|
2388
|
+
when "select"
|
2389
|
+
fieldType = SodaSelectField
|
2390
|
+
event['do'] = 'select_list'
|
2391
|
+
@curEl = getField(event)
|
2392
|
+
when "radio"
|
2393
|
+
fieldType = SodaRadioField
|
2394
|
+
event['do'] = 'radio'
|
2395
|
+
@curEl = getField(event)
|
2396
|
+
when "link"
|
2397
|
+
fieldType = SodaField
|
2398
|
+
@curEl = eventLink(event)
|
2399
|
+
when "td"
|
2400
|
+
fieldType = SodaField
|
2401
|
+
event['do'] = 'cell'
|
2402
|
+
@curEl = getField(event)
|
2403
|
+
when "tr"
|
2404
|
+
fieldType = SodaField
|
2405
|
+
event['do'] = 'row'
|
2406
|
+
@curEl = getField(event)
|
2407
|
+
when "div"
|
2408
|
+
fieldType = SodaField
|
2409
|
+
@curEl = getField(event)
|
2410
|
+
when "hidden"
|
2411
|
+
fieldType = SodaField
|
2412
|
+
@curEl = getField(event)
|
2413
|
+
when "li"
|
2414
|
+
fieldType = SodaLiField
|
2415
|
+
@curEl = getField(event)
|
2416
|
+
else
|
2417
|
+
if (@SIGNAL_STOP != false)
|
2418
|
+
exit(-1)
|
2419
|
+
end
|
2420
|
+
|
2421
|
+
# if its none of the above assume it is a field
|
2422
|
+
fieldType = SodaField
|
2423
|
+
@curEl = getField(event)
|
2424
|
+
end # end case #
|
2425
|
+
|
2426
|
+
if ( (@curEl == nil) && (event['required'] == false) )
|
2427
|
+
next
|
2428
|
+
end
|
2429
|
+
|
2430
|
+
if (@curEl == nil)
|
2431
|
+
if (event.key?("exists"))
|
2432
|
+
exists = getStringBool(event['exists'])
|
2433
|
+
|
2434
|
+
if (exists != false)
|
2435
|
+
e_dump = SodaUtils.DumpEvent(event)
|
2436
|
+
@rep.log("No Element found for event!\n",
|
2437
|
+
SodaUtils::ERROR)
|
2438
|
+
@rep.rep
|
2439
|
+
@rep.log("Event Dump for unfound element: #{e_dump}!\n",
|
2440
|
+
SodaUtils::EVENT)
|
2441
|
+
end
|
2442
|
+
else
|
2443
|
+
e_dump = SodaUtils.DumpEvent(event)
|
2444
|
+
@rep.ReportFailure("No Element found for event!\n")
|
2445
|
+
@rep.log("Event Dump for unfound element: #{e_dump}!\n",
|
2446
|
+
SodaUtils::EVENT)
|
2447
|
+
end
|
2448
|
+
|
2449
|
+
next
|
2450
|
+
end
|
2451
|
+
|
2452
|
+
jswait = true
|
2453
|
+
if (event.key?("jscriptevent") &&
|
2454
|
+
(replaceVars(event['jscriptevent']) == "onkeyup"))
|
2455
|
+
if (event.key?('jswait'))
|
2456
|
+
jswait = false if (event['jswait'] =~ /false/i)
|
2457
|
+
end
|
2458
|
+
|
2459
|
+
js = replaceVars(event['jscriptevent'])
|
2460
|
+
fieldType.jsevent(@curEl, js, jswait)
|
2461
|
+
elsif (event.key?("jscriptevent"))
|
2462
|
+
if (event.key?('jswait'))
|
2463
|
+
jswait = false if (event['jswait'] =~ /false/i)
|
2464
|
+
end
|
2465
|
+
js = replaceVars(event['jscriptevent'])
|
2466
|
+
fieldType.jsevent(@curEl, js, jswait)
|
2467
|
+
end
|
2468
|
+
|
2469
|
+
# If we have a field here is the default actions
|
2470
|
+
# that can be done on it
|
2471
|
+
if (@curEl)
|
2472
|
+
eventFieldAction(event, fieldType)
|
2473
|
+
end
|
2474
|
+
|
2475
|
+
if (browser_closed != true && jswait != false)
|
2476
|
+
CheckJavaScriptErrors()
|
2477
|
+
end
|
2478
|
+
|
2479
|
+
rescue Exception=>e
|
2480
|
+
@FAILEDTESTS.push(@currentTestFile)
|
2481
|
+
@exceptionExit = true
|
2482
|
+
@rep.log("Exception in test: \"#{@currentTestFile}\", Line: " +
|
2483
|
+
"#{event['line_number']}!\n", SodaUtils::ERROR)
|
2484
|
+
@rep.ReportException(e, true, @fileStack[@fileStack.length - 1]);
|
2485
|
+
e_dump = SodaUtils.DumpEvent(event)
|
2486
|
+
@rep.log("Event Dump From Exception: #{e_dump}!\n",
|
2487
|
+
SodaUtils::EVENT)
|
2488
|
+
|
2489
|
+
if (exception_event != nil)
|
2490
|
+
@rep.log("Running Exception Handler.\n", SodaUtils::WARN)
|
2491
|
+
@exceptionExit = false
|
2492
|
+
handleEvents(exception_event['children'])
|
2493
|
+
@rep.log("Finished Exception Handler.\n", SodaUtils::WARN)
|
2494
|
+
@exceptionExit = true
|
2495
|
+
end
|
2496
|
+
|
2497
|
+
result = -1
|
2498
|
+
ensure
|
2499
|
+
if (@exceptionExit)
|
2500
|
+
@exceptionExit = false
|
2501
|
+
return -1
|
2502
|
+
end
|
2503
|
+
end # end rescue & ensure #
|
2504
|
+
end # end event's for loop #
|
2505
|
+
end # end top most for loop #
|
2506
|
+
|
2507
|
+
|
2508
|
+
if (exception_event != nil)
|
2509
|
+
if (exception_event.key?('alwaysrun'))
|
2510
|
+
run = getStringBool(exception_event['alwaysrun'])
|
2511
|
+
if (run)
|
2512
|
+
PrintDebug("Exception Handler: alwaysrun = '#{run}'.\n")
|
2513
|
+
PrintDebug("Running Exception Handler.\n")
|
2514
|
+
result = handleEvents(exception_event['children'])
|
2515
|
+
PrintDebug("Exception Handler: Finished.\n")
|
2516
|
+
end
|
2517
|
+
end
|
2518
|
+
end
|
2519
|
+
|
2520
|
+
return result
|
2521
|
+
end
|
2522
|
+
|
2523
|
+
###############################################################################
|
2524
|
+
# SetReporter -- method
|
2525
|
+
# This method sets the reporter object for soda. Really only used for
|
2526
|
+
# sodamachine.
|
2527
|
+
#
|
2528
|
+
# Input:
|
2529
|
+
# reporter: This is the reporter object for soda to use.
|
2530
|
+
#
|
2531
|
+
# Results:
|
2532
|
+
# None.
|
2533
|
+
#
|
2534
|
+
###############################################################################
|
2535
|
+
def SetReporter(reporter)
|
2536
|
+
@rep = reporter
|
2537
|
+
end
|
2538
|
+
|
2539
|
+
###############################################################################
|
2540
|
+
# run -- Method
|
2541
|
+
# This method executes a test file.
|
2542
|
+
#
|
2543
|
+
# Params:
|
2544
|
+
# file: The Soda test file.
|
2545
|
+
# rerun: true/false, this tells soda that this tests is a rerun of a
|
2546
|
+
# failed test.
|
2547
|
+
#
|
2548
|
+
# Results:
|
2549
|
+
# returns a SodaReport object.
|
2550
|
+
#
|
2551
|
+
###############################################################################
|
2552
|
+
def run(file, rerun = false)
|
2553
|
+
result = 0
|
2554
|
+
master_result = 0
|
2555
|
+
thread_soda = nil
|
2556
|
+
thread_timeout = (60 * 5) # 5 minutes #
|
2557
|
+
time_check = nil
|
2558
|
+
|
2559
|
+
@currentTestFile = file
|
2560
|
+
@exceptionExit = false
|
2561
|
+
@fileStack.push(file)
|
2562
|
+
@rep = SodaReporter.new(file, @saveHtml, @resultsDir, 0, nil, rerun);
|
2563
|
+
SetGlobalVars()
|
2564
|
+
|
2565
|
+
script = getScript(file)
|
2566
|
+
if (script != nil)
|
2567
|
+
@currentTestFile = file
|
2568
|
+
thread_soda = Thread.new {
|
2569
|
+
result = handleEvents(script)
|
2570
|
+
}
|
2571
|
+
|
2572
|
+
while (thread_soda.alive?)
|
2573
|
+
$mutex.synchronize {
|
2574
|
+
time_check = Time.now()
|
2575
|
+
time_diff = time_check - $global_time
|
2576
|
+
time_diff = Integer(time_diff)
|
2577
|
+
|
2578
|
+
if (time_diff >= thread_timeout)
|
2579
|
+
msg = "Soda watchdog timed out after #{time_diff} seconds!\n"
|
2580
|
+
@rep.ReportFailure(msg)
|
2581
|
+
PrintDebug("Global Time was: #{$global_time}\n")
|
2582
|
+
PrintDebug("Timeout Time was: #{time_check}\n")
|
2583
|
+
result = -1
|
2584
|
+
thread_soda.exit()
|
2585
|
+
break
|
2586
|
+
end
|
2587
|
+
}
|
2588
|
+
sleep(10)
|
2589
|
+
end
|
2590
|
+
|
2591
|
+
if (result != -1)
|
2592
|
+
thread_soda.join()
|
2593
|
+
end
|
2594
|
+
|
2595
|
+
if (result != 0)
|
2596
|
+
master_result = -1
|
2597
|
+
end
|
2598
|
+
else
|
2599
|
+
msg = "Failed trying to run soda test: \"#{@currentTestFile}\"!\n"
|
2600
|
+
@rep.ReportFailure(msg)
|
2601
|
+
end
|
2602
|
+
|
2603
|
+
@rep.SodaPrintCurrentReport()
|
2604
|
+
@rep.EndTestReport()
|
2605
|
+
@rep.ReportHTML()
|
2606
|
+
|
2607
|
+
return master_result
|
2608
|
+
end
|
2609
|
+
|
2610
|
+
###############################################################################
|
2611
|
+
# GetCurrentBrowser -- Method
|
2612
|
+
# This method get the current Watir browser object.
|
2613
|
+
#
|
2614
|
+
# Input:
|
2615
|
+
# None.
|
2616
|
+
#
|
2617
|
+
# Output:
|
2618
|
+
# Returns the current watir browser object.
|
2619
|
+
#
|
2620
|
+
###############################################################################
|
2621
|
+
def GetBrowser()
|
2622
|
+
return @browser
|
2623
|
+
end
|
2624
|
+
|
2625
|
+
end
|
2626
|
+
|
2627
|
+
end
|
2628
|
+
|