rwebunit 0.8.9 → 0.9.4

Sign up to get free protection for your applications and to get access to all the features.
data/CHANGELOG CHANGED
@@ -1,5 +1,31 @@
1
1
  CHANGELOG
2
2
  =========
3
+
4
+ == 0.9.4
5
+ - change test_context => context, avoid confusing Ruby test
6
+ - refactored driver.rb
7
+
8
+ == 0.9.3
9
+ - add method failsafe {}
10
+
11
+ == 0.9.2
12
+ - sleep 0.5 seconds after clicking popup window
13
+ - save current page
14
+ - (0.9.1.1) support rspec 1.1.4: at exit hook
15
+
16
+ == 0.9.1 (2008-05-26)
17
+ - support storing page source during execution
18
+
19
+ == 0.9 (2008-05-21)
20
+ - support new syntax
21
+ spec "" do
22
+ scenario "1" do
23
+ end
24
+
25
+ story "2" do
26
+ end
27
+ end
28
+
3
29
  == 0.8.9
4
30
  - support Watir 1.5.4 zippy mode, set it as default
5
31
 
data/Rakefile CHANGED
@@ -1,68 +1,68 @@
1
- require 'rubygems'
2
- require 'rake/testtask'
3
- require 'rake/rdoctask'
4
-
5
- Gem::manage_gems
6
- require 'rake/gempackagetask'
7
-
8
- $:.unshift(File.dirname(__FILE__) + "/lib")
9
- #require 'rwebunit'
10
-
11
- desc "Default task"
12
- task :default => [ :clean, :test, :doc, :gem]
13
-
14
- desc "Clean generated files"
15
- task :clean do
16
- rm_rf 'pkg'
17
- rm_rf 'doc'
18
- end
19
-
20
- # run the unit tests
21
- Rake::TestTask.new("test") { |t|
22
- t.test_files = FileList['test/test*.rb']
23
- t.verbose= true
24
- }
25
-
26
- # Generate the RDoc documentation
27
- Rake::RDocTask.new { |rdoc|
28
- rdoc.rdoc_dir = 'doc'
29
- rdoc.title = 'rWebUnit'
30
- rdoc.template = "#{ENV['template']}.rb" if ENV['template']
31
- rdoc.rdoc_files.include('README')
32
- rdoc.rdoc_files.include('lib/rwebunit.rb')
33
- rdoc.rdoc_files.include('lib/rwebunit/*.rb')
34
- }
35
-
36
- spec = Gem::Specification.new do |s|
37
- s.platform= Gem::Platform::RUBY
38
- s.name = "rwebunit"
39
- s.version = "0.8.9"
40
- s.summary = "An wrap of WATIR/FireWatir for functional testing of web applications"
41
- # s.description = ""
42
-
43
- s.author = "Zhimin Zhan"
44
- s.email = "zhimin@agileway.net"
45
- s.homepage= "http://code.google.com/p/rwebunit/"
46
- # s.rubyforge_project = ""
47
-
48
- s.has_rdoc = true
49
- s.requirements << 'none'
50
- s.require_path = "lib"
51
- s.autorequire = "rwebunit"
52
-
53
- s.files = [ "Rakefile", "README", "CHANGELOG", "MIT-LICENSE" ]
54
- # s.files = s.files + Dir.glob( "bin/**/*" ).delete_if { |item| item.include?( "\.svn" ) }
55
- s.files = s.files + Dir.glob( "lib/**/*" ).delete_if { |item| item.include?( "\.svn" ) }
56
- s.files = s.files + Dir.glob( "test/**/*" ).delete_if { |item| item.include?( "\.svn" ) }
57
- s.files = s.files + Dir.glob( "sample/**/*" ).delete_if { |item| item.include?( "\.svn" ) }
58
- s.files = s.files + Dir.glob( "docs/**/*" ).delete_if { |item| item.include?( "\.svn" ) }
59
-
60
- # s.add_dependency("watir", ">= 1.5.3")
61
- # s.add_dependency("firewatir", ">= 1.1")
62
- end
63
-
64
- Rake::GemPackageTask.new(spec) do |pkg|
65
- pkg.need_zip = true
66
- end
67
-
68
-
1
+ require 'rubygems'
2
+ require 'rake/testtask'
3
+ require 'rake/rdoctask'
4
+
5
+ Gem::manage_gems
6
+ require 'rake/gempackagetask'
7
+
8
+ $:.unshift(File.dirname(__FILE__) + "/lib")
9
+ #require 'rwebunit'
10
+
11
+ desc "Default task"
12
+ task :default => [ :clean, :test, :doc, :gem]
13
+
14
+ desc "Clean generated files"
15
+ task :clean do
16
+ rm_rf 'pkg'
17
+ rm_rf 'doc'
18
+ end
19
+
20
+ # run the unit tests
21
+ Rake::TestTask.new("test") { |t|
22
+ t.test_files = FileList['test/test*.rb']
23
+ t.verbose= true
24
+ }
25
+
26
+ # Generate the RDoc documentation
27
+ Rake::RDocTask.new { |rdoc|
28
+ rdoc.rdoc_dir = 'doc'
29
+ rdoc.title = 'rWebUnit'
30
+ rdoc.template = "#{ENV['template']}.rb" if ENV['template']
31
+ rdoc.rdoc_files.include('README')
32
+ rdoc.rdoc_files.include('lib/rwebunit.rb')
33
+ rdoc.rdoc_files.include('lib/rwebunit/*.rb')
34
+ }
35
+
36
+ spec = Gem::Specification.new do |s|
37
+ s.platform= Gem::Platform::RUBY
38
+ s.name = "rwebunit"
39
+ s.version = "0.9.4"
40
+ s.summary = "An wrap of WATIR/FireWatir for functional testing of web applications"
41
+ # s.description = ""
42
+
43
+ s.author = "Zhimin Zhan"
44
+ s.email = "zhimin@agileway.net"
45
+ s.homepage= "http://code.google.com/p/rwebunit/"
46
+ s.rubyforge_project = "rwebunit"
47
+
48
+ s.has_rdoc = true
49
+ s.requirements << 'none'
50
+ s.require_path = "lib"
51
+ s.autorequire = "rwebunit"
52
+
53
+ s.files = [ "Rakefile", "README", "CHANGELOG", "MIT-LICENSE" ]
54
+ # s.files = s.files + Dir.glob( "bin/**/*" ).delete_if { |item| item.include?( "\.svn" ) }
55
+ s.files = s.files + Dir.glob( "lib/**/*" ).delete_if { |item| item.include?( "\.svn" ) }
56
+ s.files = s.files + Dir.glob( "test/**/*" ).delete_if { |item| item.include?( "\.svn" ) }
57
+ s.files = s.files + Dir.glob( "sample/**/*" ).delete_if { |item| item.include?( "\.svn" ) }
58
+ s.files = s.files + Dir.glob( "docs/**/*" ).delete_if { |item| item.include?( "\.svn" ) }
59
+ s.add_dependency(%q<rspec>, [">= 1.1.4"])
60
+ # s.add_dependency("watir", ">= 1.5.4")
61
+ # s.add_dependency("firewatir", ">= 1.1")
62
+ end
63
+
64
+ Rake::GemPackageTask.new(spec) do |pkg|
65
+ pkg.need_zip = true
66
+ end
67
+
68
+
@@ -0,0 +1,107 @@
1
+ module Spec
2
+ module Extensions
3
+ module Main
4
+
5
+ alias :spec :describe
6
+ alias :specification :describe
7
+
8
+ end
9
+ end
10
+ end
11
+
12
+
13
+ module Spec
14
+ module Example
15
+ module ExampleGroupMethods
16
+
17
+ alias_method :scenario, :it
18
+ alias_method :story, :it
19
+ end
20
+ end
21
+ end
22
+
23
+ module Spec
24
+ module Runner
25
+ class SpecParser
26
+ def example_group_at_line(source, line_number)
27
+ find_above(source, line_number, /^\s*(context|describe|specification|spec)\s+(.*)\s+do/)
28
+ end
29
+
30
+ def example_at_line(source, line_number)
31
+ find_above(source, line_number, /^\s*(specify|it|story|scenario)\s+(.*)\s+do/)
32
+ end
33
+ end
34
+ end
35
+ end
36
+
37
+ module Spec
38
+ module Runner
39
+ class << self
40
+ def register_at_exit_hook # :nodoc:
41
+ #ignore at exit hook
42
+ end
43
+ end
44
+ end
45
+ end
46
+
47
+ module Spec
48
+ class Translator
49
+
50
+ def translate_line(line)
51
+ # Translate deprecated mock constraints
52
+ line.gsub!(/:any_args/, 'any_args')
53
+ line.gsub!(/:anything/, 'anything')
54
+ line.gsub!(/:boolean/, 'boolean')
55
+ line.gsub!(/:no_args/, 'no_args')
56
+ line.gsub!(/:numeric/, 'an_instance_of(Numeric)')
57
+ line.gsub!(/:string/, 'an_instance_of(String)')
58
+
59
+ return line if line =~ /(should_not|should)_receive/
60
+
61
+ line.gsub!(/(^\s*)context([\s*|\(]['|"|A-Z])/, '\1describe\2')
62
+ line.gsub!(/(^\s*)spec([\s*|\(]['|"|A-Z])/, '\1describe\2') #new
63
+ line.gsub!(/(^\s*)specification([\s*|\(]['|"|A-Z])/, '\1describe\2') #new
64
+ line.gsub!(/(^\s*)specify([\s*|\(]['|"|A-Z])/, '\1it\2')
65
+ line.gsub!(/(^\s*)scenario([\s*|\(]['|"|A-Z])/, '\1it\2') #new
66
+ line.gsub!(/(^\s*)story([\s*|\(]['|"|A-Z])/, '\1it\2') #new
67
+ line.gsub!(/(^\s*)context_setup(\s*[do|\{])/, '\1before(:all)\2')
68
+ line.gsub!(/(^\s*)context_teardown(\s*[do|\{])/, '\1after(:all)\2')
69
+ line.gsub!(/(^\s*)setup(\s*[do|\{])/, '\1before(:each)\2')
70
+ line.gsub!(/(^\s*)teardown(\s*[do|\{])/, '\1after(:each)\2')
71
+
72
+ if line =~ /(.*\.)(should_not|should)(?:_be)(?!_)(.*)/m
73
+ pre = $1
74
+ should = $2
75
+ post = $3
76
+ be_or_equal = post =~ /(<|>)/ ? "be" : "equal"
77
+
78
+ return "#{pre}#{should} #{be_or_equal}#{post}"
79
+ end
80
+
81
+ if line =~ /(.*\.)(should_not|should)_(?!not)\s*(.*)/m
82
+ pre = $1
83
+ should = $2
84
+ post = $3
85
+
86
+ post.gsub!(/^raise/, 'raise_error')
87
+ post.gsub!(/^throw/, 'throw_symbol')
88
+
89
+ unless standard_matcher?(post)
90
+ post = "be_#{post}"
91
+ end
92
+
93
+ # Add parenthesis
94
+ post.gsub!(/^(\w+)\s+([\w|\.|\,|\(.*\)|\'|\"|\:|@| ]+)(\})/, '\1(\2)\3') # inside a block
95
+ post.gsub!(/^(redirect_to)\s+(.*)/, '\1(\2)') # redirect_to, which often has http:
96
+ post.gsub!(/^(\w+)\s+([\w|\.|\,|\(.*\)|\{.*\}|\'|\"|\:|@| ]+)/, '\1(\2)')
97
+ post.gsub!(/(\s+\))/, ')')
98
+ post.gsub!(/\)\}/, ') }')
99
+ post.gsub!(/^(\w+)\s+(\/.*\/)/, '\1(\2)') #regexps
100
+ line = "#{pre}#{should} #{post}"
101
+ end
102
+
103
+ line
104
+ end
105
+ end
106
+ end
107
+
@@ -8,7 +8,7 @@ module RWebUnit
8
8
  ##
9
9
  # Store test optionns
10
10
  #
11
- class TestContext
11
+ class Context
12
12
  attr_accessor :base_url
13
13
 
14
14
  def initialize(base_url)
@@ -1,424 +1,279 @@
1
- # The Mixin is normally included in the spec/tests and pages, provide
2
- # convenient methods to drive the browser.
3
- #
4
- # Instead of
5
- # browser.click_button("submit")
6
- # You can just use
7
- # click_button("submit")
8
- #
9
-
10
- module RWebUnit
11
- module Driver
12
-
13
- # Verify the next page following an operation.
14
- #
15
- # Typical usage:
16
- # login_page.click_login
17
- # expect_page HomePage
18
- def expect_page(page_clazz)
19
- page_clazz.new(@web_tester)
20
- end
21
-
22
- # Using Ruby block syntax to create interesting domain specific language,
23
- # may be appeal to someone.
24
-
25
- # Example:
26
- # on @page do |i|
27
- # i.enter_text('btn1')
28
- # i.click_button('btn1')
29
- # end
30
- def on(page, &block)
31
- yield page
32
- end
33
-
34
- def test_context
35
- @web_tester.test_context
36
- end
37
-
38
- def begin_at(url)
39
- @web_tester.begin_at(url)
40
- end
41
-
42
- def ie;
43
- @web_tester.ie;
44
- end
45
-
46
- def close_browser
47
- @web_tester.close_browser unless ENV['ITEST_LEAVE_BROWSER_OPEN_AFTER_RUN'] == "true"
48
- end
49
- alias close_ie close_browser
50
-
51
- # browser navigation
52
- def go_back;
53
- @web_tester.go_back;
54
- end
55
- def go_forward;
56
- @web_tester.go_forward;
57
- end
58
-
59
- def goto_page(page)
60
- operation_delay
61
- @web_tester.goto_page(page);
62
- end
63
- def refresh;
64
- @web_tester.refresh;
65
- end
66
- alias refresh_page refresh
67
-
68
- def attach_browser(how, what)
69
- WebTester.attach_browser(how, what)
70
- end
71
-
72
- ##
73
- # Delegate to WebTester
74
- #
75
-
76
- # Depends on which object type, you can use following attribute
77
- # More details: http://wiki.openqa.org/display/WTR/Methods+supported+by+Element
78
- #
79
- # :id Used to find an element that has an "id=" attribute. Since each id should be unique, according to the XHTML specification, this is recommended as the most reliable method to find an object. *
80
- # :name Used to find an element that has a "name=" attribute. This is useful for older versions of HTML, but "name" is deprecated in XHTML. *
81
- # :value Used to find a text field with a given default value, or a button with a given caption, or a text field
82
- # :text Used for links, spans, divs and other element that contain text.
83
- # :index Used to find the nth element of the specified type on a page. For example, button(:index, 2) finds the second button. Current versions of WATIR use 1-based indexing, but future versions will use 0-based indexing.
84
- # :class Used for an element that has a "class=" attribute.
85
- # :title Used for an element that has a "title=" attribute.
86
- # :xpath Finds the item using xpath query.
87
- # :method Used only for forms, the method attribute of a form is either GET or POST.
88
- # :action Used only for form elements, specifies the URL where the form is to be submitted.
89
- # :href Used to identify a link by its "href=" attribute.
90
- # :src Used to identify an image by its URL.
91
- #
92
-
93
- # area <area> tags
94
- # button <input> tags with type=button, submit, image or reset
95
- # check_box <input> tags with type=checkbox
96
- # div <div> tags
97
- # form <form> tags
98
- # frame frames, including both the <frame> elements and the corresponding pages
99
- # h1 - h6 <h1>, <h2>, <h3>, <h4>, <h5>, <h6> tags
100
- # hidden <input> tags with type=hidden
101
- # image <img> tags
102
- # label <label> tags (including "for" attribute)
103
- # li <li> tags
104
- # link <a> (anchor) tags
105
- # map <map> tags
106
- # radio <input> tags with the type=radio; known as radio buttons
107
- # select_list <select> tags, known as drop-downs or drop-down lists
108
- # span <span> tags
109
- # table <table> tags, including row and cell methods for accessing nested elements
110
- # text_field <input> tags with the type=text (single-line), type=textarea (multi-line), and type=password
111
- # p <p> (paragraph) tags, because
112
- def area(*args)
113
- @web_tester.area(*args);
114
- end
115
- def button(*args)
116
- @web_tester.button(*args);
117
- end
118
- def cell(*args)
119
- @web_tester.cell(*args);
120
- end
121
- alias td cell
122
-
123
- def checkbox(*args)
124
- @web_tester.checkbox(*args);
125
- end
126
- alias check_box checkbox # seems watir doc is wrong, checkbox not check_box
127
-
128
- def div(*args)
129
- @web_tester.div(*args);
130
- end
131
- def form(*args)
132
- @web_tester.form(*args);
133
- end
134
- def frame(*args)
135
- @web_tester.frame(*args);
136
- end
137
- def h1(*args)
138
- @web_tester.h1(*args);
139
- end
140
- def h2(*args)
141
- @web_tester.h2(*args);
142
- end
143
- def h3(*args)
144
- @web_tester.h3(*args);
145
- end
146
- def h4(*args)
147
- @web_tester.h4(*args);
148
- end
149
- def h5(*args)
150
- @web_tester.h5(*args);
151
- end
152
- def h6(*args)
153
- @web_tester.h6(*args);
154
- end
155
- def hidden(*args)
156
- @web_tester.hidden(*args);
157
- end
158
- def image(*args)
159
- @web_tester.image(*args);
160
- end
161
- def li(*args)
162
- @web_tester.li(*args);
163
- end
164
- def link(*args)
165
- @web_tester.link(*args);
166
- end
167
- def map(*args)
168
- @web_tester.map(*args);
169
- end
170
- def pre(*args)
171
- @web_tester.pre(*args);
172
- end
173
- def row(*args)
174
- @web_tester.row(*args);
175
- end
176
- alias tr row
177
-
178
- def radio(*args)
179
- @web_tester.radio(*args);
180
- end
181
- def select_list(*args)
182
- @web_tester.select_list(*args);
183
- end
184
- def span(*args)
185
- @web_tester.span(*args);
186
- end
187
- def table(*args)
188
- @web_tester.table(*args);
189
- end
190
- def text_field(*args)
191
- @web_tester.text_field(*args);
192
- end
193
-
194
- def paragraph(*args)
195
- @web_tester.paragraph(*args);
196
- end
197
- def file_field(*args)
198
- @web_tester.file_field(*args);
199
- end
200
- def label(*args)
201
- @web_tester.label(*args);
202
- end
203
-
204
- def contains_text(text)
205
- @web_tester.contains_text(text);
206
- end
207
-
208
-
209
- def images;
210
- @web_tester.images;
211
- end
212
- def links;
213
- @web_tester.links;
214
- end
215
- def buttons;
216
- @web_tester.buttons;
217
- end
218
- def select_lists;
219
- @web_tester.select_lists;
220
- end
221
- def checkboxes;
222
- @web_tester.checkboxes;
223
- end
224
- def radios;
225
- @web_tester.radios;
226
- end
227
- def text_fields;
228
- @web_tester.text_fields;
229
- end
230
-
231
-
232
- # enter text into a text field
233
- def enter_text(elementName, elementValue)
234
- operation_delay
235
- @web_tester.set_form_element(elementName, elementValue)
236
- end
237
- alias set_form_element enter_text
238
-
239
-
240
- #links
241
- def click_link_with_text(link_text)
242
- operation_delay
243
- @web_tester.click_link_with_text(link_text)
244
- end
245
- alias click_link click_link_with_text
246
-
247
- def click_link_with_id(link_id)
248
- operation_delay
249
- @web_tester.click_link_with_id(link_id)
250
- end
251
-
252
- ##
253
- # buttons
254
-
255
- # submit the form using the first (index) submit button
256
- def submit()
257
- operation_delay
258
- @web_tester.submit()
259
- end
260
-
261
- # click a form submit button with specified button id
262
- def submit(button_id)
263
- operation_delay
264
- @web_tester.submit(button_id)
265
- end
266
-
267
- def click_button_with_id(button_id)
268
- operation_delay
269
- @web_tester.click_button_with_id(button_id)
270
- end
271
-
272
- def click_button_with_caption(caption)
273
- operation_delay
274
- @web_tester.click_button_with_caption(caption)
275
- end
276
- alias click_button_with_text click_button_with_caption
277
- alias click_button click_button_with_caption
278
-
279
- def click_button_with_image_src_contains(image_filename)
280
- operation_delay
281
- found = nil
282
- raise "no buttons in this page" if buttons.length <= 0
283
- buttons.each { |btn|
284
- if btn && btn.src && btn.src.include?(image_filename) then
285
- found = btn
286
- break
287
- end
288
- }
289
- raise "not image button with src: #{image_filename} found" if found.nil?
290
- found.click
291
- end
292
- alias click_button_with_image click_button_with_image_src_contains
293
-
294
- def click_button_with_value(value)
295
- operation_delay
296
- @web_tester.click_button_with_value(value)
297
- end
298
-
299
- # Radios
300
- def click_radio_option(name, value)
301
- operation_delay
302
- @web_tester.click_radio_option(name, value)
303
- end
304
- alias click_radio_button click_radio_option
305
-
306
- def clear_radio_option(name, value)
307
- operation_delay
308
- @web_tester.clear_radio_option(name, value)
309
- end
310
- alias clear_radio_button clear_radio_option
311
-
312
- # Filefield
313
- def select_file_for_upload(file_field, file_path)
314
- operation_delay
315
- @web_tester.select_file_for_upload(file_field, file_path)
316
- end
317
-
318
- # Check one or more checkboxes with same name, can accept a string or an array of string as values checkbox, pass array as values will try to set mulitple checkboxes.
319
- #
320
- # page.check_checkbox('bad_ones', 'Chicken Little')
321
- # page.check_checkbox('good_ones', ['Cars', 'Toy Story'])
322
- def check_checkbox(name, value=nil)
323
- operation_delay
324
- @web_tester.check_checkbox(name, value)
325
- end
326
-
327
- # Uncheck one or more checkboxes with same name
328
- def uncheck_checkbox(name, value=nil)
329
- operation_delay
330
- @web_tester.uncheck_checkbox(name, value)
331
- end
332
-
333
- # combo box
334
- def select_option(selectName, option)
335
- operation_delay
336
- @web_tester.select_option(selectName, option)
337
- end
338
-
339
- def new_popup_window(options)
340
- @web_tester.new_popup_window(options)
341
- end
342
-
343
- # Wait for specific seconds for an Ajax update finish.
344
- # Trick: In your Rails application,
345
- # :loading => "Element.show('search_indicator');
346
- # :complete => "Element.hide('search_indicator');
347
- #
348
- # <%= image_tag("indicator.gif", :id => 'search_indicator', :style => 'display:none') %>
349
- #
350
- # Typical usage:
351
- # ajax_wait_for_element("search_indicator", 30)
352
- # ajax_wait_for_element("search_indicator", 30, "show")
353
- # ajax_wait_for_element("search_indicator", 30, "hide")
354
- # ajax_wait_for_element("search_indicator", 30, "show", 5) # check every 5 seconds
355
- #
356
- # Warning: this method has not been fully tested, if you are not using Rails, change your parameter accordingly.
357
- #
358
- def ajax_wait_for_element(element_id, seconds, status='show', check_interval=2)
359
- count = 0
360
- check_interval = 2 if check_interval < 1 or check_interval > seconds
361
- while count < (seconds / check_interval) do
362
- search_indicator = @web_tester.element_by_id(element_id)
363
- search_indicator_outer_html = search_indicator.outerHtml if search_indicator
364
- if status == 'hide'
365
- return true if search_indicator_outer_html and !search_indicator_outer_html.include?('style="DISPLAY: none"')
366
- else
367
- return true if search_indicator_outer_html and search_indicator_outer_html.include?('style="DISPLAY: none"')
368
- end
369
- sleep check_interval if check_interval > 0 and check_interval < 5 * 60 # wait max 5 minutes
370
- count += 1
371
- end
372
- return false
373
- end
374
-
375
- def wait_for_element(element_id, timeout = 30, interval = 0.5)
376
- start_time = Time.now
377
- until @web_tester.element_by_id(element_id) do
378
- sleep(interval)
379
- if (Time.now - start_time) > timeout
380
- raise RuntimeError, "failed to find element: #{element_id} for max #{timeout}"
381
- end
382
- end
383
- end
384
-
385
- def element_text(elem_id)
386
- @web_tester.element_value(elem_id)
387
- end
388
-
389
- # fail the test if user can perform the operation
390
- def shall_not_allow
391
- operation_performed_ok = false
392
- begin
393
- yield
394
- operation_performed_ok = true
395
- rescue
396
- end
397
-
398
- raise "Operation shall not be allowed" if operation_performed_ok
399
- end
400
- alias do_not_allow shall_not_allow
401
-
402
- # ---
403
- # For debugging
404
- # ---
405
- def dump_response(stream = nil)
406
- @web_tester.dump_response(stream)
407
- end
408
-
409
- def click_popup_window(button, waitTime= 9, user_input=nil )
410
- @web_tester.start_clicker(button, waitTime, user_input)
411
- end
412
-
413
- def operation_delay
414
- begin
415
- if ENV['ITEST_OPERATION_DELAY'] && ENV['ITEST_OPERATION_DELAY'].to_i > 0 && ENV['ITEST_OPERATION_DELAY'].to_f < 30000 then # max 30 seconds
416
- sleep(ENV['ITEST_OPERATION_DELAY'].to_f / 1000)
417
- end
418
- rescue => e
419
- # ignore
420
- end
421
- end
422
-
423
- end
424
- end
1
+ # The Mixin is normally included in the spec/tests and pages, provide
2
+ # convenient methods to drive the browser.
3
+ #
4
+ # Instead of
5
+ # browser.click_button("submit")
6
+ # You can just use
7
+ # click_button("submit")
8
+ #
9
+
10
+ module RWebUnit
11
+ module Driver
12
+
13
+ # Verify the next page following an operation.
14
+ #
15
+ # Typical usage:
16
+ # login_page.click_login
17
+ # expect_page HomePage
18
+ def expect_page(page_clazz)
19
+ page_clazz.new(@web_tester)
20
+ end
21
+
22
+ # Using Ruby block syntax to create interesting domain specific language,
23
+ # may be appeal to someone.
24
+
25
+ # Example:
26
+ # on @page do |i|
27
+ # i.enter_text('btn1')
28
+ # i.click_button('btn1')
29
+ # end
30
+ def on(page, &block)
31
+ yield page
32
+ end
33
+
34
+ # fail the test if user can perform the operation
35
+ #
36
+ # Example:
37
+ # shall_not_allow { 1/0 }
38
+ def shall_not_allow(&block)
39
+ operation_performed_ok = false
40
+ begin
41
+ yield
42
+ operation_performed_ok = true
43
+ rescue
44
+ end
45
+ raise "Operation shall not be allowed" if operation_performed_ok
46
+ end
47
+ alias do_not_allow shall_not_allow
48
+
49
+ def allow(&block)
50
+ operation_performed_ok = false
51
+ begin
52
+ yield
53
+ operation_performed_ok = true
54
+ rescue
55
+ end
56
+ operation_performed_ok
57
+ end
58
+
59
+ # try operation, ignore if errors occur
60
+ #
61
+ # Example:
62
+ # failsafe { click_link("Logout") } # try logout, but it still OK if not being able to (already logout))
63
+ def failsafe(&block)
64
+ begin
65
+ yield
66
+ rescue =>e
67
+ end
68
+ end
69
+ alias fail_safe failsafe
70
+
71
+ def context
72
+ @web_tester.context
73
+ end
74
+
75
+ def begin_at(url)
76
+ @web_tester.begin_at(url)
77
+ end
78
+
79
+ def ie
80
+ @web_tester.ie
81
+ end
82
+
83
+ def close_browser
84
+ @web_tester.close_browser unless ENV['ITEST_LEAVE_BROWSER_OPEN_AFTER_RUN'] == "true"
85
+ end
86
+ alias close_ie close_browser
87
+
88
+ [:go_back, :go_forward, :refresh].each do |method|
89
+ define_method(method) do
90
+ @web_tester.send(method)
91
+ end
92
+ end
93
+ alias refresh_page refresh
94
+
95
+ def goto_page(page)
96
+ operation_delay
97
+ @web_tester.goto_page(page);
98
+ end
99
+
100
+ def attach_browser(how, what)
101
+ WebTester.attach_browser(how, what)
102
+ end
103
+
104
+ ##
105
+ # Delegate to WebTester
106
+ #
107
+
108
+ # Depends on which object type, you can use following attribute
109
+ # More details: http://wiki.openqa.org/display/WTR/Methods+supported+by+Element
110
+ #
111
+ # :id Used to find an element that has an "id=" attribute. Since each id should be unique, according to the XHTML specification, this is recommended as the most reliable method to find an object. *
112
+ # :name Used to find an element that has a "name=" attribute. This is useful for older versions of HTML, but "name" is deprecated in XHTML. *
113
+ # :value Used to find a text field with a given default value, or a button with a given caption, or a text field
114
+ # :text Used for links, spans, divs and other element that contain text.
115
+ # :index Used to find the nth element of the specified type on a page. For example, button(:index, 2) finds the second button. Current versions of WATIR use 1-based indexing, but future versions will use 0-based indexing.
116
+ # :class Used for an element that has a "class=" attribute.
117
+ # :title Used for an element that has a "title=" attribute.
118
+ # :xpath Finds the item using xpath query.
119
+ # :method Used only for forms, the method attribute of a form is either GET or POST.
120
+ # :action Used only for form elements, specifies the URL where the form is to be submitted.
121
+ # :href Used to identify a link by its "href=" attribute.
122
+ # :src Used to identify an image by its URL.
123
+ #
124
+
125
+ # area <area> tags
126
+ # button <input> tags with type=button, submit, image or reset
127
+ # check_box <input> tags with type=checkbox
128
+ # div <div> tags
129
+ # form <form> tags
130
+ # frame frames, including both the <frame> elements and the corresponding pages
131
+ # h1 - h6 <h1>, <h2>, <h3>, <h4>, <h5>, <h6> tags
132
+ # hidden <input> tags with type=hidden
133
+ # image <img> tags
134
+ # label <label> tags (including "for" attribute)
135
+ # li <li> tags
136
+ # link <a> (anchor) tags
137
+ # map <map> tags
138
+ # radio <input> tags with the type=radio; known as radio buttons
139
+ # select_list <select> tags, known as drop-downs or drop-down lists
140
+ # span <span> tags
141
+ # table <table> tags, including row and cell methods for accessing nested elements
142
+ # text_field <input> tags with the type=text (single-line), type=textarea (multi-line), and type=password
143
+ # p <p> (paragraph) tags, because
144
+ [:area, :button, :cell, :checkbox, :div, :form, :frame, :h1, :h2, :h3, :h4, :h5, :h6, :hidden, :image, :li, :link, :map, :pre, :row, :radio, :select_list, :span, :table, :text_field, :paragraph, :file_field, :label].each do |method|
145
+ define_method method do |*args|
146
+ @web_tester.send(method, *args)
147
+ end
148
+ end
149
+ alias td cell
150
+ alias check_box checkbox # seems watir doc is wrong, checkbox not check_box
151
+ alias tr row
152
+
153
+ def contains_text(text)
154
+ @web_tester.contains_text(text);
155
+ end
156
+
157
+ [:images, :links, :buttons, :select_lists, :checkboxes, :radios, :text_fields].each do |method|
158
+ define_method method do
159
+ @web_tester.send(method)
160
+ end
161
+ end
162
+
163
+ # Check one or more checkboxes with same name, can accept a string or an array of string as values checkbox, pass array as values will try to set mulitple checkboxes.
164
+ #
165
+ # page.check_checkbox('bad_ones', 'Chicken Little')
166
+ # page.check_checkbox('good_ones', ['Cars', 'Toy Story'])
167
+
168
+ [:set_form_element, :click_link_with_text, :click_link_with_id, :submit, :click_button_with_id, :click_button_with_caption, :click_button_with_value, :click_radio_option, :clear_radio_option, :select_file_for_upload, :check_checkbox, :uncheck_checkbox, :select_option].each do |method|
169
+ define_method method do |*args|
170
+ @web_tester.send(method, *args)
171
+ end
172
+ end
173
+
174
+ alias enter_text set_form_element
175
+ alias click_link click_link_with_text
176
+ alias click_button_with_text click_button_with_caption
177
+ alias click_button click_button_with_caption
178
+ alias click_radio_button click_radio_option
179
+ alias clear_radio_button clear_radio_option
180
+
181
+ def click_button_with_image_src_contains(image_filename)
182
+ operation_delay
183
+ found = nil
184
+ raise "no buttons in this page" if buttons.length <= 0
185
+ buttons.each { |btn|
186
+ if btn && btn.src && btn.src.include?(image_filename) then
187
+ found = btn
188
+ break
189
+ end
190
+ }
191
+ raise "not image button with src: #{image_filename} found" if found.nil?
192
+ found.click
193
+ end
194
+ alias click_button_with_image click_button_with_image_src_contains
195
+
196
+ def new_popup_window(options)
197
+ @web_tester.new_popup_window(options)
198
+ end
199
+
200
+ # Wait for specific seconds for an Ajax update finish.
201
+ # Trick: In your Rails application,
202
+ # :loading => "Element.show('search_indicator');
203
+ # :complete => "Element.hide('search_indicator');
204
+ #
205
+ # <%= image_tag("indicator.gif", :id => 'search_indicator', :style => 'display:none') %>
206
+ #
207
+ # Typical usage:
208
+ # ajax_wait_for_element("search_indicator", 30)
209
+ # ajax_wait_for_element("search_indicator", 30, "show")
210
+ # ajax_wait_for_element("search_indicator", 30, "hide")
211
+ # ajax_wait_for_element("search_indicator", 30, "show", 5) # check every 5 seconds
212
+ #
213
+ # Warning: this method has not been fully tested, if you are not using Rails, change your parameter accordingly.
214
+ #
215
+ def ajax_wait_for_element(element_id, seconds, status='show', check_interval=2)
216
+ count = 0
217
+ check_interval = 2 if check_interval < 1 or check_interval > seconds
218
+ while count < (seconds / check_interval) do
219
+ search_indicator = @web_tester.element_by_id(element_id)
220
+ search_indicator_outer_html = search_indicator.outerHtml if search_indicator
221
+ if status == 'hide'
222
+ return true if search_indicator_outer_html and !search_indicator_outer_html.include?('style="DISPLAY: none"')
223
+ else
224
+ return true if search_indicator_outer_html and search_indicator_outer_html.include?('style="DISPLAY: none"')
225
+ end
226
+ sleep check_interval if check_interval > 0 and check_interval < 5 * 60 # wait max 5 minutes
227
+ count += 1
228
+ end
229
+ return false
230
+ end
231
+
232
+ def wait_for_element(element_id, timeout = 30, interval = 0.5)
233
+ start_time = Time.now
234
+ until @web_tester.element_by_id(element_id) do
235
+ sleep(interval)
236
+ if (Time.now - start_time) > timeout
237
+ raise RuntimeError, "failed to find element: #{element_id} for max #{timeout}"
238
+ end
239
+ end
240
+ end
241
+
242
+ # Warning: this does not work well with Firefox yet.
243
+ def element_text(elem_id)
244
+ @web_tester.element_value(elem_id)
245
+ end
246
+
247
+
248
+ # ---
249
+ # For debugging
250
+ # ---
251
+ def dump_response(stream = nil)
252
+ @web_tester.dump_response(stream)
253
+ end
254
+
255
+ def save_current_page(to_dir = ENV['TEMP_DIR'] || "C:\\temp")
256
+ Dir.mkdir(to_dir) unless File.exists?(to_dir)
257
+ file_name = Time.now.strftime("%m%d%H%M%S") + ".html"
258
+ file = File.join(to_dir, file_name)
259
+ File.new(file, "w").puts page_source
260
+ end
261
+
262
+ def click_popup_window(button, wait_time= 9, user_input=nil )
263
+ @web_tester.start_clicker(button, wait_time, user_input)
264
+ sleep 0.5
265
+ end
266
+
267
+ # Support of iTest to ajust the intervals between keystroke/mouse operations
268
+ def operation_delay
269
+ begin
270
+ if ENV['ITEST_OPERATION_DELAY'] && ENV['ITEST_OPERATION_DELAY'].to_i > 0 && ENV['ITEST_OPERATION_DELAY'].to_f < 30000 then # max 30 seconds
271
+ sleep(ENV['ITEST_OPERATION_DELAY'].to_f / 1000)
272
+ end
273
+ rescue => e
274
+ # ignore
275
+ end
276
+ end
277
+
278
+ end
279
+ end
@@ -57,7 +57,6 @@ module RWebUnit
57
57
  sprintf("%c", random_number(97, 122)) if lowercase
58
58
  sprintf("%c", random_number(65, 90)) unless lowercase
59
59
  end
60
- alias randomChar random_char
61
60
 
62
61
  def random_digit()
63
62
  sprintf("%c", random_number(48, 57))
@@ -4,6 +4,7 @@
4
4
  #***********************************************************
5
5
  require File.join(File.dirname(__FILE__), 'assert')
6
6
  require File.join(File.dirname(__FILE__), 'driver')
7
+ require 'fileutils'
7
8
 
8
9
  module RWebUnit
9
10
 
@@ -23,7 +24,7 @@ module RWebUnit
23
24
 
24
25
  include RWebUnit::Assert
25
26
  include RWebUnit::Driver
26
-
27
+
27
28
  # browser: passed to do assertion within the page
28
29
  # page_text: text used to identify the page, title will be the first candidate
29
30
  attr_accessor :browser, :page_text
@@ -32,10 +33,11 @@ module RWebUnit
32
33
  @web_tester = web_tester
33
34
  @page_text = page_text
34
35
  begin
36
+ snapshot if ENV['ITEST_DUMP_PAGE'] == 'true'
35
37
  delay = ENV['ITEST_PAGE_DELAY'].to_i
36
38
  sleep(delay)
37
39
  rescue => e
38
- end
40
+ end
39
41
  assert_on_page
40
42
  end
41
43
 
@@ -78,6 +80,20 @@ module RWebUnit
78
80
  end
79
81
  alias include contains?
80
82
 
83
+
84
+ def snapshot
85
+ if ENV['ITEST_DUMP_DIR']
86
+ spec_run_id = ENV['ITEST_RUNNING_SPEC_ID'] || "unknown"
87
+ spec_run_dir_name = spec_run_id.to_s.rjust(4, "0") unless spec_run_id == "unknown"
88
+ spec_run_dir = File.join(ENV['ITEST_DUMP_DIR'], spec_run_dir_name)
89
+ Dir.mkdir(spec_run_dir) unless File.exists?(spec_run_dir)
90
+ file_name = Time.now.strftime("%m%d%H%M%S") + "_" + self.class.name.gsub("", "") + ".html"
91
+ file = File.join(ENV['ITEST_DUMP_DIR'], spec_run_dir_name, file_name)
92
+ page_source = browser.page_source
93
+ File.new(file, "w").puts source
94
+ end
95
+ end
96
+
81
97
  end
82
98
 
83
99
  end
@@ -26,7 +26,7 @@ module RWebUnit
26
26
  end
27
27
 
28
28
  def open_browser(baseUrl, relativeUrl)
29
- test_context.base_url = baseUrl
29
+ context.base_url = baseUrl
30
30
  begin_at(relativeUrl)
31
31
  end
32
32
  alias open_ie open_browser
@@ -13,9 +13,11 @@ rescue LoadError => e
13
13
  end
14
14
 
15
15
  begin
16
+ require 'rubygems'
16
17
  require "firewatir";
17
18
  $firewatir_loaded = true
18
19
  rescue LoadError => e
20
+ puts e
19
21
  $firewatir_loaded = false
20
22
  end
21
23
 
@@ -41,15 +43,15 @@ module RWebUnit
41
43
  #
42
44
  class WebTester
43
45
 
44
- attr_accessor :test_context
46
+ attr_accessor :context
45
47
 
46
48
  def initialize(base_url = nil, options = {})
47
49
  default_options = {:speed => "zippy",
48
50
  :visible => true,
49
51
  :highlight_colour => 'yellow',
50
- :close_others => true}
52
+ :close_others => true}
51
53
  options = default_options.merge options
52
- @test_context = TestContext.new base_url if base_url
54
+ @context = Context.new base_url if base_url
53
55
 
54
56
  if (options[:firefox] && $firewatir_loaded) || ($firewatir_loaded and !$watir_loaded)
55
57
  @@browser = FireWatir::Firefox.start(base_url)
@@ -212,11 +214,11 @@ module RWebUnit
212
214
  end
213
215
 
214
216
  def base_url=(new_base_url)
215
- if @test_context
216
- @test_conext.base_url = new_base_url
217
+ if @context
218
+ @conext.base_url = new_base_url
217
219
  return
218
220
  end
219
- @test_context = TestContext.new base_url
221
+ @context = Context.new base_url
220
222
  end
221
223
 
222
224
  def is_firefox?
@@ -248,8 +250,8 @@ module RWebUnit
248
250
  end
249
251
 
250
252
  def full_url(relative_url)
251
- if @test_context && @test_context.base_url
252
- @test_context.base_url + relative_url
253
+ if @context && @context.base_url
254
+ @context.base_url + relative_url
253
255
  else
254
256
  relative_url
255
257
  end
data/lib/rwebunit.rb CHANGED
@@ -1,26 +1,28 @@
1
- #***********************************************************
2
- #* Copyright (c) 2006, Zhimin Zhan.
3
- #* Distributed open-source, see full license in MIT-LICENSE
4
- #***********************************************************
5
-
6
- # Load active_support, so that we can use 1.days.ago
7
- begin
8
- require 'active_support/basic_object'
9
- require 'active_support/duration'
10
- rescue LoadError => no_as1_err
11
- # active_support 2.0 loaded error
12
- end
13
- require 'active_support/core_ext'
14
-
15
- # Extra full path to load libraries
16
- require File.dirname(__FILE__) + "/rwebunit/test_utils"
17
- require File.dirname(__FILE__) + "/rwebunit/web_page"
18
- require File.dirname(__FILE__) + "/rwebunit/assert"
19
- #This cause some unit test loaded, to use it, load specifiically
20
- #require File.dirname(__FILE__) + "/rwebunit/web_testcase"
21
- require File.dirname(__FILE__) + "/rwebunit/web_tester"
22
- require File.dirname(__FILE__) + "/rwebunit/test_context"
23
- require File.dirname(__FILE__) + "/rwebunit/driver"
24
- require File.dirname(__FILE__) + "/rwebunit/rspec_helper"
25
-
26
-
1
+ #***********************************************************
2
+ #* Copyright (c) 2006, Zhimin Zhan.
3
+ #* Distributed open-source, see full license in MIT-LICENSE
4
+ #***********************************************************
5
+
6
+ # Load active_support, so that we can use 1.days.ago
7
+ begin
8
+ require 'active_support/basic_object'
9
+ require 'active_support/duration'
10
+ rescue LoadError => no_as1_err
11
+ # active_support 2.0 loaded error
12
+ end
13
+ require 'active_support/core_ext'
14
+
15
+ require 'spec'
16
+
17
+ # Extra full path to load libraries
18
+ require File.dirname(__FILE__) + "/rwebunit/test_utils"
19
+ require File.dirname(__FILE__) + "/rwebunit/web_page"
20
+ require File.dirname(__FILE__) + "/rwebunit/assert"
21
+ #This cause some unit test loaded, to use it, load specifiically
22
+ #require File.dirname(__FILE__) + "/rwebunit/web_testcase"
23
+ require File.dirname(__FILE__) + "/rwebunit/web_tester"
24
+ require File.dirname(__FILE__) + "/rwebunit/context"
25
+ require File.dirname(__FILE__) + "/rwebunit/driver"
26
+ require File.dirname(__FILE__) + "/rwebunit/rspec_helper"
27
+ require File.dirname(__FILE__) + "/rspec_extensions"
28
+ #require File.dirname(__FILE__) + "/rwebunit/matchers/"
@@ -0,0 +1,39 @@
1
+ $:.unshift File.join(File.dirname(__FILE__), "..", "lib/rwebunit")
2
+ $:.unshift File.dirname(__FILE__)
3
+
4
+ require "driver.rb"
5
+ require "web_tester.rb"
6
+ require 'test/unit'
7
+
8
+ class TestDriver < Test::Unit::TestCase
9
+ include RWebUnit::Driver
10
+
11
+ def setup
12
+ @web_tester = "dummy"
13
+ end
14
+
15
+ def teardown
16
+ end
17
+
18
+ def test_fail_safe
19
+ fail_safe {raise "X"}
20
+ end
21
+
22
+ def test_expect_page
23
+ new_page = expect_page String
24
+ assert_equal("dummy", new_page)
25
+ end
26
+
27
+ def test_on
28
+ page = []
29
+ on(page) do |i|
30
+ i << "0"
31
+ i << "1"
32
+ end
33
+ assert_equal(["0", "1"], page)
34
+ end
35
+
36
+ def test_shall_not_allow
37
+ shall_not_allow {1 / 0}
38
+ end
39
+ end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rwebunit
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.8.9
4
+ version: 0.9.4
5
5
  platform: ruby
6
6
  authors:
7
7
  - Zhimin Zhan
@@ -9,10 +9,19 @@ autorequire: rwebunit
9
9
  bindir: bin
10
10
  cert_chain: []
11
11
 
12
- date: 2008-05-01 00:00:00 +10:00
12
+ date: 2008-08-20 00:00:00 +10:00
13
13
  default_executable:
14
- dependencies: []
15
-
14
+ dependencies:
15
+ - !ruby/object:Gem::Dependency
16
+ name: rspec
17
+ type: :runtime
18
+ version_requirement:
19
+ version_requirements: !ruby/object:Gem::Requirement
20
+ requirements:
21
+ - - ">="
22
+ - !ruby/object:Gem::Version
23
+ version: 1.1.4
24
+ version:
16
25
  description:
17
26
  email: zhimin@agileway.net
18
27
  executables: []
@@ -26,16 +35,18 @@ files:
26
35
  - README
27
36
  - CHANGELOG
28
37
  - MIT-LICENSE
38
+ - lib/rspec_extensions.rb
29
39
  - lib/rwebunit
30
40
  - lib/rwebunit/assert.rb
41
+ - lib/rwebunit/context.rb
31
42
  - lib/rwebunit/driver.rb
32
43
  - lib/rwebunit/rspec_helper.rb
33
- - lib/rwebunit/test_context.rb
34
44
  - lib/rwebunit/test_utils.rb
35
45
  - lib/rwebunit/web_page.rb
36
46
  - lib/rwebunit/web_testcase.rb
37
47
  - lib/rwebunit/web_tester.rb
38
48
  - lib/rwebunit.rb
49
+ - test/test_driver.rb
39
50
  - test/test_test_utils.rb
40
51
  - sample/kangxi_home_webtest.rb
41
52
  - sample/kangxi_httpcaller_webtest.rb
@@ -69,8 +80,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
69
80
  version:
70
81
  requirements:
71
82
  - none
72
- rubyforge_project:
73
- rubygems_version: 1.1.0
83
+ rubyforge_project: rwebunit
84
+ rubygems_version: 1.2.0
74
85
  signing_key:
75
86
  specification_version: 2
76
87
  summary: An wrap of WATIR/FireWatir for functional testing of web applications