soda 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
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
+