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 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
+