rwebunit 0.8.9 → 0.9.4

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