jmonteiro-jmonteiro-safariwatir 0.3.5.1

Sign up to get free protection for your applications and to get access to all the features.
data/README.rdoc ADDED
@@ -0,0 +1,49 @@
1
+ "There's something eerily tingly about seeing a browser run by itself."
2
+ http://twitter.com/swombat/status/1280692921
3
+
4
+ = SafariWatir
5
+
6
+ * http://safariwatir.rubyforge.org
7
+ * http://rubyforge.org/mailman/listinfo/safariwatir-general
8
+ * http://twitter.com/SafariWatir
9
+
10
+ == DESCRIPTION:
11
+
12
+ We are putting Watir on Safari.
13
+ The original Watir (Web Application Testing in Ruby) project supports only IE on Windows.
14
+ This project aims at adding Watir support for Safari on the Mac.
15
+
16
+ == Requirements
17
+
18
+ Mac OS X running Safari. Some features require you to turn on "Enable access for assistive devices" in System Preferences > Universal Access.
19
+
20
+
21
+ == SYNOPSIS:
22
+
23
+ require 'rubygems'
24
+ require 'safariwatir'
25
+
26
+ browser = Watir::Safari.new
27
+ browser.goto("http://google.com")
28
+ browser.text_field(:name, "q").set("obtiva")
29
+ browser.button(:name, "btnI").click
30
+ puts "FAILURE" unless browser.contains_text("software")
31
+
32
+ == INSTALL:
33
+
34
+ [sudo] gem install jmonteiro-safariwatir --source="http://gems.github.com"
35
+
36
+ or
37
+
38
+ git clone git://github.com/jmonteiro/safariwatir.git
39
+ cd safariwatir
40
+ rake install
41
+
42
+ == RUNNING SAFARIWATIR AGAINST WATIR'S CORE TESTS
43
+
44
+ # First, install the SafariWatir gem (see above)
45
+ svn checkout https://svn.openqa.org/svn/watir/trunk
46
+ cd trunk/watir
47
+ cp unittests/options.yml.example unittests/options.yml
48
+ # Edit unittests/options.yml and set browser: safari
49
+ ruby unittests/core_tests.rb
data/Rakefile ADDED
@@ -0,0 +1,13 @@
1
+ require 'rubygems'
2
+ require 'rake'
3
+ require 'echoe'
4
+
5
+ Echoe.new('safariwatir', '0.3.5') do | config |
6
+ config.summary = %q{Automated testing tool for web applications.}
7
+ config.description = %q{WATIR stands for "Web Application Testing in Ruby". See WATIR project for more information. This is a Safari-version of the original IE-only WATIR.}
8
+ config.url = 'http://safariwatir.rubyforge.org/'
9
+ config.author = 'Dave Hoover'
10
+ config.email = 'dave@obtiva.com'
11
+ config.ignore_pattern = ['tmp/*', 'script/*']
12
+ config.development_dependencies = ["rb-appscript"]
13
+ end
@@ -0,0 +1,573 @@
1
+ require 'watir/exceptions'
2
+ require 'safariwatir/scripter'
3
+ require 'safariwatir/core_ext'
4
+
5
+ module Watir
6
+ include Watir::Exception
7
+
8
+ module PageContainer
9
+ def html
10
+ @scripter.document_html
11
+ end
12
+
13
+ def text
14
+ @scripter.document_text
15
+ end
16
+
17
+ def title
18
+ @scripter.document_title
19
+ end
20
+ end
21
+
22
+ module Container
23
+ attr_reader :scripter
24
+ private :scripter
25
+
26
+ DEFAULT_TYPING_LAG = 0.08
27
+
28
+ def set_fast_speed
29
+ @scripter.typing_lag = 0
30
+ end
31
+
32
+ def set_slow_speed
33
+ @scripter.typing_lag = DEFAULT_TYPING_LAG
34
+ end
35
+
36
+ def speed=(how_fast)
37
+ case how_fast
38
+ when :fast : set_fast_speed
39
+ when :slow : set_slow_speed
40
+ else
41
+ raise ArgumentError, "Invalid speed: #{how_fast}"
42
+ end
43
+ end
44
+
45
+ module Clickable
46
+ def click
47
+ @scripter.highlight(self) do
48
+ click_element
49
+ end
50
+ end
51
+ end
52
+
53
+ class AlertWindow
54
+ def_init :scripter
55
+
56
+ def click
57
+ @scripter.click_alert
58
+ end
59
+ end
60
+
61
+ class SecurityWarningWindow
62
+ def initialize(scripter, url)
63
+ @scripter = scripter
64
+ @url = url
65
+ end
66
+
67
+ def continue
68
+ handle_click("Continue")
69
+ end
70
+
71
+ def cancel
72
+ handle_click("Cancel")
73
+ end
74
+
75
+ private
76
+ def handle_click(button)
77
+ if @url
78
+ @scripter.navigate_to(@url) do
79
+ @scripter.click_security_warning(button)
80
+ end
81
+ else
82
+ @scripter.click_security_warning(button)
83
+ end
84
+ end
85
+ end
86
+
87
+ class Frame
88
+ include Container
89
+ include PageContainer
90
+
91
+ attr_reader :name
92
+
93
+ def initialize(scripter, name)
94
+ @name = name
95
+ @scripter = scripter.for_frame(self)
96
+ end
97
+ end
98
+
99
+ class HtmlElement
100
+ def_init :scripter, :how, :what
101
+ attr_reader :how, :what
102
+
103
+ # overridden in derivitives
104
+ def tag
105
+ raise RuntimeError, "tag not provided for #{name}"
106
+ end
107
+
108
+ # overridden in derivitives
109
+ def speak
110
+ @scripter.speak("#{name}'s don't know how to speak.")
111
+ end
112
+
113
+ def exists?
114
+ @scripter.element_exists?(self)
115
+ end
116
+ alias :exist? :exists?
117
+
118
+ def name
119
+ self.class.name.split("::").last
120
+ end
121
+
122
+ def focus
123
+ @scripter.focus(self)
124
+ end
125
+
126
+ def mouse_over
127
+ @scripter.mouse_over_element(self)
128
+ end
129
+
130
+ def operate(&block)
131
+ scripter_suffix = OPERATIONS[how]
132
+ if scripter_suffix.kind_of? Hash
133
+ scripter_suffix = scripter_suffix[name]
134
+ end
135
+ if scripter_suffix.nil?
136
+ raise "SafariWatir does not currently support finding by #{how}"
137
+ end
138
+ @scripter.send("operate_#{scripter_suffix}", self, &block)
139
+ end
140
+
141
+ OPERATIONS = {
142
+ :id => "by_id",
143
+ :index => "by_index",
144
+ :class => "by_class",
145
+ :name => "by_name",
146
+ :text => { "Link" => "on_link", "Label" => "by_text" },
147
+ :url => "on_link",
148
+ :value => "by_input_value",
149
+ :caption => "by_input_value",
150
+ :src => "by_src",
151
+ # TODO: write the corresponding operate_by_label method in scripter
152
+ # :label => "by_label",
153
+ }
154
+ end
155
+
156
+ class Form < HtmlElement
157
+ def_init :scripter, :how, :what
158
+
159
+ def submit
160
+ @scripter.submit_form(self)
161
+ end
162
+
163
+ def tag; "FORM"; end
164
+ end
165
+
166
+ class InputElement < HtmlElement
167
+ include Clickable
168
+
169
+ def speak
170
+ @scripter.speak_value_of(self)
171
+ end
172
+
173
+ def enabled?
174
+ !@scripter.element_disabled?(self)
175
+ end
176
+
177
+ def tag; "INPUT"; end
178
+
179
+ # Hook for derivitives
180
+ def by_value; end
181
+ end
182
+
183
+ class ContentElement < HtmlElement
184
+ include Clickable
185
+ include Container
186
+
187
+ def html
188
+ @scripter.get_html_for(self)
189
+ end
190
+
191
+ def text
192
+ @scripter.get_text_for(self)
193
+ end
194
+
195
+ def speak
196
+ @scripter.speak_text_of(self)
197
+ end
198
+ end
199
+
200
+ class Image < HtmlElement
201
+ include Clickable
202
+
203
+ def tag; "IMG"; end
204
+ end
205
+
206
+ class Button < InputElement
207
+ end
208
+
209
+ class Checkbox < InputElement
210
+ def_init :scripter, :how, :what, :value
211
+
212
+ def by_value
213
+ @value
214
+ end
215
+
216
+ # Contributed by Kyle Campos
217
+ def checked?
218
+ @scripter.checkbox_is_checked?(self)
219
+ end
220
+
221
+ def set(check_it = true)
222
+ return if check_it && checked?
223
+ return if !check_it && !checked?
224
+ click
225
+ end
226
+ end
227
+
228
+ class Div < ContentElement
229
+ def tag; "DIV"; end
230
+ end
231
+
232
+ class P < ContentElement
233
+ def tag; "P"; end
234
+ end
235
+
236
+ class Label < ContentElement
237
+ def tag; "LABEL"; end
238
+
239
+ def target_id
240
+ @scripter.get_target_for(self)
241
+ end
242
+ end
243
+
244
+ class Link < ContentElement
245
+ def click
246
+ @scripter.highlight(self) do
247
+ click_link
248
+ end
249
+ end
250
+
251
+ def tag; "A"; end
252
+ end
253
+
254
+ class Radio < Checkbox
255
+ end
256
+
257
+ class SelectList < InputElement
258
+ def select(label)
259
+ option(:text, label).select
260
+ end
261
+
262
+ def select_value(value)
263
+ option(:value, value).select
264
+ end
265
+
266
+ def option(how, what)
267
+ Option.new(@scripter, self, how, what)
268
+ end
269
+
270
+ def selected_values
271
+ values = []
272
+ index = 1
273
+ loop do
274
+ option = option(:index, index)
275
+ break unless option.exists?
276
+ values << option if option.selected?
277
+ index += 1
278
+ end
279
+ values.map {|o| o.text } #TODO?
280
+ end
281
+
282
+ def selected_value
283
+ selected_values.first
284
+ end
285
+
286
+ def speak
287
+ @scripter.speak_options_for(self)
288
+ end
289
+
290
+ def tag; "SELECT"; end
291
+ end
292
+
293
+ class Option < InputElement
294
+ def_init :scripter, :select_list, :how, :what
295
+
296
+ def select
297
+ @scripter.highlight(self) do
298
+ select_option
299
+ end
300
+ end
301
+
302
+ def operate(&block)
303
+ @select_list.operate(&block)
304
+ end
305
+
306
+ def exists?
307
+ @scripter.option_exists?(self)
308
+ end
309
+ alias :exist? :exists?
310
+
311
+ def selected?
312
+ @scripter.option_selected?(self)
313
+ end
314
+
315
+ def text
316
+ @scripter.get_text_for(self)
317
+ end
318
+
319
+ def tag; "OPTION"; end
320
+ end
321
+
322
+ class Span < ContentElement
323
+ def tag; "SPAN"; end
324
+ end
325
+
326
+ class Table
327
+ def_init :scripter, :how, :what
328
+ attr_reader :how, :what
329
+
330
+ def each
331
+ # TODO
332
+ end
333
+
334
+ def [](index)
335
+ TableRow.new(@scripter, :index, index, self)
336
+ end
337
+
338
+ def row_count
339
+ # TODO
340
+ end
341
+
342
+ def column_count
343
+ # TODO
344
+ end
345
+
346
+ def tag; "TABLE"; end
347
+ end
348
+
349
+ class TableRow
350
+ def initialize(scripter, how, what, table = nil)
351
+ @scripter = scripter
352
+ @how = how
353
+ @what = what
354
+ @table = table
355
+ end
356
+
357
+ attr_reader :table, :how, :what
358
+
359
+ def each
360
+ # TODO
361
+ end
362
+
363
+ def [](index)
364
+ TableCell.new(@scripter, :index, index, self)
365
+ end
366
+
367
+ def column_count
368
+ # TODO
369
+ end
370
+
371
+ def tag; "TR"; end
372
+ end
373
+
374
+ class TableCell < ContentElement
375
+ def initialize(scripter, how, what, row = nil)
376
+ @scripter = scripter.for_table(self)
377
+ set_slow_speed # TODO: Need to inherit this somehow
378
+
379
+ @how = how
380
+ @what = what
381
+ @row = row
382
+ end
383
+
384
+ attr_reader :how, :what, :row
385
+
386
+ def operate(&block)
387
+ @scripter.operate_by_table_cell(self, &block)
388
+ end
389
+
390
+ def tag; "TD"; end
391
+ end
392
+
393
+ class TextField < InputElement
394
+ def set(value)
395
+ value = value.to_s
396
+ @scripter.focus(self)
397
+ @scripter.highlight(self) do
398
+ clear_text_input
399
+ value.length.times do |i|
400
+ append_text_input(value[i, 1])
401
+ end
402
+ end
403
+ @scripter.blur(self)
404
+ end
405
+
406
+ def getContents
407
+ @scripter.get_value_for(self)
408
+ end
409
+
410
+ def verify_contains(expected)
411
+ actual = getContents
412
+ case expected
413
+ when Regexp
414
+ actual.match(expected) != nil
415
+ else
416
+ expected == actual
417
+ end
418
+ end
419
+ end
420
+
421
+ class Password < TextField
422
+ end
423
+
424
+
425
+ # Elements
426
+
427
+ def button(how, what)
428
+ Button.new(scripter, how, what)
429
+ end
430
+
431
+ def cell(how, what)
432
+ TableCell.new(scripter, how, what)
433
+ end
434
+
435
+ def checkbox(how, what, value = nil)
436
+ Checkbox.new(scripter, how, what, value)
437
+ end
438
+
439
+ def div(how, what)
440
+ Div.new(scripter, how, what)
441
+ end
442
+
443
+ def p(how, what)
444
+ P.new(scripter, how, what)
445
+ end
446
+
447
+ def form(how, what)
448
+ Form.new(scripter, how, what)
449
+ end
450
+
451
+ def frame(name)
452
+ Frame.new(scripter, name)
453
+ end
454
+
455
+ def image(how, what)
456
+ Image.new(scripter, how, what)
457
+ end
458
+
459
+ def label(how, what)
460
+ Label.new(scripter, how, what)
461
+ end
462
+
463
+ def link(how, what)
464
+ Link.new(scripter, how, what)
465
+ end
466
+
467
+ def password(how, what)
468
+ Password.new(scripter, how, what)
469
+ end
470
+
471
+ def radio(how, what, value = nil)
472
+ Radio.new(scripter, how, what, value)
473
+ end
474
+
475
+ def row(how, what)
476
+ TableRow.new(scripter, how, what)
477
+ end
478
+
479
+ def select_list(how, what)
480
+ SelectList.new(scripter, how, what)
481
+ end
482
+
483
+ def span(how, what)
484
+ Span.new(scripter, how, what)
485
+ end
486
+
487
+ def table(how, what)
488
+ Table.new(scripter, how, what)
489
+ end
490
+
491
+ def text_field(how, what)
492
+ TextField.new(scripter, how, what)
493
+ end
494
+
495
+ def contains_text(what)
496
+ case what
497
+ when Regexp:
498
+ text =~ what
499
+ when String:
500
+ text.index(what)
501
+ else
502
+ raise MissingWayOfFindingObjectException
503
+ end
504
+ end
505
+ end
506
+
507
+ class Safari
508
+ include Container
509
+ include PageContainer
510
+
511
+ def self.start(url = nil)
512
+ safari = new
513
+ safari.goto(url) if url
514
+ safari
515
+ end
516
+
517
+ def initialize
518
+ @scripter = AppleScripter.new(JavaScripter.new)
519
+ @scripter.ensure_window_ready
520
+ set_slow_speed
521
+ end
522
+
523
+ # URL of page
524
+ def url
525
+ scripter.url
526
+ end
527
+
528
+ # Hide's Safari
529
+ def hide
530
+ scripter.hide
531
+ end
532
+
533
+ def close
534
+ scripter.close
535
+ end
536
+
537
+ def quit
538
+ scripter.quit
539
+ end
540
+
541
+ def alert
542
+ AlertWindow.new(scripter)
543
+ end
544
+
545
+ def security_warning
546
+ SecurityWarningWindow.new(scripter)
547
+ end
548
+
549
+ def security_warning_at(url)
550
+ SecurityWarningWindow.new(scripter, url)
551
+ end
552
+
553
+ def goto(url)
554
+ scripter.navigate_to(url)
555
+ end
556
+
557
+ # Reloads the page
558
+ def reload
559
+ scripter.reload
560
+ end
561
+ alias :refresh :reload
562
+ end # class Safari
563
+
564
+
565
+ class WebKit < Safari
566
+ def initialize
567
+ @scripter = AppleScripter.new(JavaScripter.new, :appname => "WebKit")
568
+ @scripter.ensure_window_ready
569
+ set_slow_speed
570
+ end
571
+ end # class WebKit
572
+
573
+ end