watirsplash 0.1.9
Sign up to get free protection for your applications and to get access to all the features.
- data/History.rdoc +51 -0
- data/License.txt +24 -0
- data/README.rdoc +171 -0
- data/Rakefile +16 -0
- data/bin/watirsplash +10 -0
- data/lib/spec.opts +5 -0
- data/lib/watirsplash/autoit.rb +54 -0
- data/lib/watirsplash/html_formatter.rb +118 -0
- data/lib/watirsplash/runner.rb +97 -0
- data/lib/watirsplash/spec.rb +43 -0
- data/lib/watirsplash/spec_helper.rb +68 -0
- data/lib/watirsplash/util.rb +35 -0
- data/lib/watirsplash/version.rb +3 -0
- data/lib/watirsplash/waiter.rb +29 -0
- data/lib/watirsplash/watir.rb +151 -0
- data/lib/watirsplash.rb +11 -0
- data/spec/spec_helper_spec.rb +56 -0
- data/spec/spec_match_array_spec.rb +21 -0
- data/spec/util_spec.rb +38 -0
- data/spec/watir_ie_spec.rb +13 -0
- data/spec/watir_table_row_spec.rb +46 -0
- data/spec/watir_table_spec.rb +79 -0
- data/templates/common/config.rb +28 -0
- data/templates/common/environment.rb +17 -0
- data/templates/common/lib/common_application_helper.rb +14 -0
- data/templates/project/application_helper.rb +18 -0
- data/templates/project/config.rb +20 -0
- data/templates/project/environment.rb +13 -0
- data/templates/project/ide_runner.rb +3 -0
- data/templates/project/spec/dummy_spec.rb +44 -0
- metadata +205 -0
data/History.rdoc
ADDED
@@ -0,0 +1,51 @@
|
|
1
|
+
=== Version 0.1.9 / 2010-05-01
|
2
|
+
|
3
|
+
* Changed name of the library to WatirSplash due to name conflict
|
4
|
+
- this means that all watirspec commands are now obsolete and you have to use watirsplash commands instead
|
5
|
+
- all WatiRspec constants (module names etc) are now named as WatirSplash
|
6
|
+
|
7
|
+
=== Version 0.1.8 / 2010-04-19
|
8
|
+
|
9
|
+
* tidied up some code, no changes in functionality
|
10
|
+
|
11
|
+
=== Version 0.1.7 / 2010-04-15
|
12
|
+
|
13
|
+
* minor fix
|
14
|
+
|
15
|
+
=== Version 0.1.6 / 2010-04-08
|
16
|
+
|
17
|
+
* browser was not closed when Watir::IE#run_error_checks throwed an exception
|
18
|
+
|
19
|
+
=== Version 0.1.5 / 2010-04-08
|
20
|
+
|
21
|
+
* fixed a problem where HtmlFormatter threw an ugly exception due to the problem when browser was not opened
|
22
|
+
|
23
|
+
=== Version 0.1.4 / 2010-04-06
|
24
|
+
|
25
|
+
* added dependency for win32screenshot
|
26
|
+
|
27
|
+
=== Version 0.1.3 / 2010-04-06
|
28
|
+
|
29
|
+
* fixed a bug where inner table was not shown with Watir::Table#to_a when it was not a direct child, but some other element was in between for example form, span, div etc.
|
30
|
+
|
31
|
+
=== Version 0.1.2 / 2010-04-05
|
32
|
+
|
33
|
+
* Added match_array matcher for RSpec for using with Array when regular expressions are needed. It is useful when verifying html tables with #to_a method.
|
34
|
+
expected_array = ["1", "2", /\d+/, "3"]
|
35
|
+
|
36
|
+
["1", "2", "66", "3"].should match_array(expected_array)
|
37
|
+
table(:id => "table_id").to_a.should match_array(expected_array)
|
38
|
+
|
39
|
+
=== Version 0.1.1 / 2010-04-04
|
40
|
+
|
41
|
+
* Watir::Table#to_a and Watir::TableRow#to_a work now well with tr, th, td elements, colspan and nested tables.
|
42
|
+
This means that you can test easily tables now:
|
43
|
+
expected_table = [["one", "two"], ["three", "four"]]
|
44
|
+
table(:id => "table_id").to_a.should =~ expected_table
|
45
|
+
|
46
|
+
* removed strict version requirements for dependencies
|
47
|
+
|
48
|
+
|
49
|
+
=== Version 0.1.0 / 2010-04-03
|
50
|
+
|
51
|
+
First release of WatiRspec, a small library for combining Watir and RSpec for browser-based functional testing in Ruby.
|
data/License.txt
ADDED
@@ -0,0 +1,24 @@
|
|
1
|
+
(The MIT License)
|
2
|
+
|
3
|
+
Copyright (c) 2010 Jarmo Pertman
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person
|
6
|
+
obtaining a copy of this software and associated documentation
|
7
|
+
files (the "Software"), to deal in the Software without
|
8
|
+
restriction, including without limitation the rights to use,
|
9
|
+
copy, modify, merge, publish, distribute, sublicense, and/or sell
|
10
|
+
copies of the Software, and to permit persons to whom the
|
11
|
+
Software is furnished to do so, subject to the following
|
12
|
+
conditions:
|
13
|
+
|
14
|
+
The above copyright notice and this permission notice shall be
|
15
|
+
included in all copies or substantial portions of the Software.
|
16
|
+
|
17
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
18
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
|
19
|
+
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
20
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
21
|
+
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
22
|
+
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
23
|
+
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
24
|
+
OTHER DEALINGS IN THE SOFTWARE
|
data/README.rdoc
ADDED
@@ -0,0 +1,171 @@
|
|
1
|
+
= WatirSplash
|
2
|
+
|
3
|
+
* Web: http://github.com/jarmo/WatirSplash
|
4
|
+
* Author: Jarmo Pertman (mailto:jarmo.p[at]gmail.com)
|
5
|
+
|
6
|
+
== DESCRIPTION:
|
7
|
+
|
8
|
+
WatirSplash is a small library for easier browser-based functional testing in Ruby.
|
9
|
+
It combines Watir (http://www.watir.com) for controlling the browser (currently mainly IE) and
|
10
|
+
RSpec (http://rspec.info) for testing framework. This powerful combination gives you
|
11
|
+
the ability to write easily well-maintained and easy-to-read specs (specifications in RSpec) so
|
12
|
+
you don't need to have any extra documentation for your applications.
|
13
|
+
|
14
|
+
WatirSplash makes it easier to use best features of both of these tools together so
|
15
|
+
you won't have to spend time on thinking how to do that yourself - you can start
|
16
|
+
testing right away!
|
17
|
+
|
18
|
+
== FEATURES:
|
19
|
+
|
20
|
+
* generate command for generating default project structure
|
21
|
+
* generate_common command for generating common ui-tests directory
|
22
|
+
* Browser will be opened and closed for each example group automatically
|
23
|
+
* You can use Watir method names directly without having to specify a browser object:
|
24
|
+
text_field(:name => "locator") # instead of @browser.text_field(:name => "locator")
|
25
|
+
* All needed libraries will be loaded and helper modules will be included automatically
|
26
|
+
* All JavaScript errors will be detected automatically
|
27
|
+
* Some additional methods to help using Watir (download_file, wait_until, wait_until! etc.)
|
28
|
+
|
29
|
+
* Custom html formatter for RSpec:
|
30
|
+
* Saves screenshot of the browser window
|
31
|
+
* Saves html of the page
|
32
|
+
* Saves all the files created/downloaded during the example and shows them on the report
|
33
|
+
* Automatically archives test results for later reviewing
|
34
|
+
|
35
|
+
== SYNOPSIS:
|
36
|
+
|
37
|
+
describe "Google" do
|
38
|
+
before :all do
|
39
|
+
goto "http://google.com"
|
40
|
+
url.should =~ /google/
|
41
|
+
end
|
42
|
+
|
43
|
+
it "has search field" do
|
44
|
+
text_field = text_field(:name => "q")
|
45
|
+
text_field.should exist
|
46
|
+
text_field.should be_visible
|
47
|
+
end
|
48
|
+
|
49
|
+
it "performs search" do
|
50
|
+
text_field(:name => "q").set "Bing"
|
51
|
+
button(:name => "btnG").click
|
52
|
+
text.should include("Bing")
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
C:\project\ui-test>watirsplash spec\google_spec.rb
|
57
|
+
Results will be saved into the directory C:/project/ui-test/results
|
58
|
+
Google
|
59
|
+
has search field
|
60
|
+
performs search
|
61
|
+
|
62
|
+
Finished in 6.782388 seconds
|
63
|
+
|
64
|
+
2 examples, 0 failures
|
65
|
+
|
66
|
+
== INSTALL:
|
67
|
+
|
68
|
+
* install Ruby 1.8.6:
|
69
|
+
http://rubyinstaller.org/
|
70
|
+
|
71
|
+
* install ImageMagick with rmagick-win32 for making the screenshots:
|
72
|
+
http://rubyforge.org/frs/?group_id=12&release_id=42049
|
73
|
+
|
74
|
+
* update RubyGems:
|
75
|
+
gem update --system
|
76
|
+
|
77
|
+
* install WatirSplash:
|
78
|
+
gem install watirsplash
|
79
|
+
|
80
|
+
== USAGE:
|
81
|
+
|
82
|
+
If you have a web-application project (it may have been written in any programming language) without any browser-based tests,
|
83
|
+
then it has probably a directory structure similar to this example:
|
84
|
+
C:\example_project
|
85
|
+
├───doc
|
86
|
+
├───lib
|
87
|
+
└───test
|
88
|
+
|
89
|
+
Now from the command line go to this directory and execute generate command:
|
90
|
+
C:\>cd example_project
|
91
|
+
|
92
|
+
C:\example_project>watirsplash generate
|
93
|
+
Creating WatirSplash project directory structure to C:/example_project/ui-test...
|
94
|
+
Done
|
95
|
+
|
96
|
+
After that the directory structure will be something like this:
|
97
|
+
C:\example_project
|
98
|
+
├───doc
|
99
|
+
├───lib
|
100
|
+
├───test
|
101
|
+
└───ui-test
|
102
|
+
└───spec
|
103
|
+
|
104
|
+
The contents of that ui-test directory will be:
|
105
|
+
ui-test\application_helper.rb
|
106
|
+
ui-test\config.rb
|
107
|
+
ui-test\environment.rb
|
108
|
+
ui-test\ide_runner.rb
|
109
|
+
|
110
|
+
ui-test\spec
|
111
|
+
ui-test\spec\dummy_spec.rb
|
112
|
+
|
113
|
+
Just check out all the files to see some example code and comments in it and execute dummy_spec.rb
|
114
|
+
to verify that everything works correctly:
|
115
|
+
watirsplash spec\dummy_spec.rb
|
116
|
+
|
117
|
+
You can have whatever directory structure for your tests just make sure that all test files have _spec.rb in
|
118
|
+
the end of their filename (if using default RSpec options).
|
119
|
+
|
120
|
+
== USAGE FOR MULTIPLE PROJECTS:
|
121
|
+
|
122
|
+
Usually you're going to write tests for multiple different projects. It would be shame if you'd
|
123
|
+
going to create all those common helper methods again for different projects or just copy-paste
|
124
|
+
the code from previous project's helpers. This is the place where ui-test-common comes into play.
|
125
|
+
|
126
|
+
ui-test-common would be a place where you can hold all your common functionality in helper
|
127
|
+
modules/methods/classes and then use those things in your tests so you won't have multiple
|
128
|
+
copies of similar or even same code in different places. So it helps you
|
129
|
+
to keep DRY (http://en.wikipedia.org/wiki/Don't_repeat_yourself).
|
130
|
+
|
131
|
+
After finding yourself in a situation where a new project comes into play, then execute
|
132
|
+
generate_common command once somewhere in a higher level of a directory tree than your project's ui-test directory
|
133
|
+
to generate ui-test-common directory:
|
134
|
+
C:\example_project>cd ..
|
135
|
+
|
136
|
+
C:\>watirsplash generate_common
|
137
|
+
Creating WatirSplash common project directory structure to C:/ui-test-common...
|
138
|
+
Done
|
139
|
+
|
140
|
+
It has a structure of:
|
141
|
+
C:\UI-TEST-COMMON
|
142
|
+
└───lib
|
143
|
+
|
144
|
+
ui-test-common\config.rb
|
145
|
+
ui-test-common\environment.rb
|
146
|
+
ui-test-common\lib
|
147
|
+
ui-test-common\lib\common_application_helper.rb
|
148
|
+
|
149
|
+
In environment.rb under project/ui-test you shall add common functionality to your project.
|
150
|
+
Add the following line before any other require statements to do that:
|
151
|
+
WatirSplash::Util.load_common
|
152
|
+
|
153
|
+
This gives you by default the access to every method in ui-test-common/lib/common_application_helper.rb
|
154
|
+
|
155
|
+
Now, in ui-test-common/config.rb change the URL to your hostname and in config.rb under project/ui-test:
|
156
|
+
URL = Config.full_url("/relative_path")
|
157
|
+
|
158
|
+
This gives you the ability to have host and port written only in one place.
|
159
|
+
|
160
|
+
Now move all the common functionality away from your project's files into ui-test-common files and start testing.
|
161
|
+
From now on, add all common functionality into ui-test-common/lib
|
162
|
+
|
163
|
+
== KNOWN PROBLEMS (& SOLUTIONS)
|
164
|
+
|
165
|
+
=== PROBLEM #1
|
166
|
+
|
167
|
+
If you see the following error message when running watirsplash:
|
168
|
+
R6034. An application has made an attempt to load the C runtime library incorrectly.
|
169
|
+
|
170
|
+
Solution:
|
171
|
+
Install Microsoft Visual C++ 2008 SP1 Redistributable Package
|
data/Rakefile
ADDED
@@ -0,0 +1,16 @@
|
|
1
|
+
require 'rake'
|
2
|
+
require 'spec/rake/spectask'
|
3
|
+
|
4
|
+
Spec::Rake::SpecTask.new(:rcov) do |t|
|
5
|
+
t.spec_files = FileList['spec/**/*_spec.rb']
|
6
|
+
t.rcov = true
|
7
|
+
t.rcov_dir = 'coverage'
|
8
|
+
t.rcov_opts << '--sort coverage --text-summary --aggregate coverage.data'
|
9
|
+
end
|
10
|
+
|
11
|
+
Spec::Rake::SpecTask.new(:spec) do |t|
|
12
|
+
t.spec_files = FileList['spec/**/*_spec.rb']
|
13
|
+
t.spec_opts << "--options" << "lib/spec.opts" <<
|
14
|
+
"--require" << "lib/watirsplash/html_formatter" <<
|
15
|
+
"--format" << "WatirSplash::HtmlFormatter:results/index.html"
|
16
|
+
end
|
data/bin/watirsplash
ADDED
@@ -0,0 +1,10 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
watirsplash_dir = File.expand_path(File.join(File.dirname(__FILE__), '..', 'lib'))
|
3
|
+
$LOAD_PATH.unshift(watirsplash_dir) unless $LOAD_PATH.include?(watirsplash_dir)
|
4
|
+
require 'watirsplash/runner'
|
5
|
+
|
6
|
+
if ARGV.size == 1 && ::WatirSplash::Runner.respond_to?(ARGV[0])
|
7
|
+
exit ::WatirSplash::Runner.send(ARGV[0])
|
8
|
+
else
|
9
|
+
exit ::WatirSplash::Runner.run
|
10
|
+
end
|
@@ -0,0 +1,54 @@
|
|
1
|
+
# Helper class for AutoIt
|
2
|
+
class AutoItHelper
|
3
|
+
extend WatirSplash::Waiter
|
4
|
+
|
5
|
+
@@autoit = Watir.autoit
|
6
|
+
|
7
|
+
class << self
|
8
|
+
# clicks save button on window with specified title,
|
9
|
+
# activates window automatically and makes sure that the click
|
10
|
+
# was successful
|
11
|
+
def click_save(window_title="File Download")
|
12
|
+
click_button(window_title, "&Save")
|
13
|
+
end
|
14
|
+
|
15
|
+
# sets edit field value to field_value on window with specified title,
|
16
|
+
# activates window automatically and makes sure that the field's
|
17
|
+
# value got changed
|
18
|
+
def set_edit(field_value, window_title="Save As")
|
19
|
+
set_field(window_title, "Edit1", field_value)
|
20
|
+
end
|
21
|
+
|
22
|
+
# sets specified field's value on window with specified title,
|
23
|
+
# activates window automatically and makes sure that the field's
|
24
|
+
# value got changed
|
25
|
+
def set_field(window_title, field_name, field_value)
|
26
|
+
wait_until! do
|
27
|
+
activate_window(window_title) &&
|
28
|
+
@@autoit.ControlFocus(window_title, "", field_name) == 1 &&
|
29
|
+
@@autoit.ControlSetText(window_title, "", field_name, field_value) == 1 &&
|
30
|
+
@@autoit.ControlGetText(window_title, "", field_name) == field_value
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
# clicks specified button on window with specified title,
|
35
|
+
# activates window automatically and makes sure that the click
|
36
|
+
# was successful
|
37
|
+
def click_button(window_title, button_name)
|
38
|
+
wait_until! do
|
39
|
+
activate_window(window_title) &&
|
40
|
+
@@autoit.ControlFocus(window_title, "", button_name) == 1 &&
|
41
|
+
@@autoit.ControlClick(window_title, "", button_name) == 1 &&
|
42
|
+
wait_until(3) {@@autoit.WinExists(window_title) == 0}
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
# makes window active with specified title
|
47
|
+
# * returns true if activation was successful and false otherwise
|
48
|
+
def activate_window(window_title)
|
49
|
+
@@autoit.WinWait(window_title, "", 1) == 1 &&
|
50
|
+
@@autoit.WinActivate(window_title) != 0 &&
|
51
|
+
@@autoit.WinActive(window_title) != 0
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
@@ -0,0 +1,118 @@
|
|
1
|
+
require 'spec/runner/formatter/html_formatter'
|
2
|
+
require 'win32screenshot'
|
3
|
+
require 'rmagick'
|
4
|
+
require 'pathname'
|
5
|
+
require 'fileutils'
|
6
|
+
|
7
|
+
module WatirSplash
|
8
|
+
# Custom RSpec formatter for WatirSplash
|
9
|
+
# * saves screenshot of the browser upon test failure
|
10
|
+
# * saves html of the browser upon test failure
|
11
|
+
# * saves javascript error dialog upon test failure
|
12
|
+
# * saves all files generated/downloaded during the test and shows them in the report
|
13
|
+
class HtmlFormatter < ::Spec::Runner::Formatter::HtmlFormatter
|
14
|
+
|
15
|
+
# currently used browser object
|
16
|
+
# needed for saving of screenshots and html
|
17
|
+
attr_writer :browser
|
18
|
+
|
19
|
+
def initialize(options, output) # :nodoc:
|
20
|
+
raise "output has to be a file path!" unless output.is_a?(String)
|
21
|
+
@output_dir = File.expand_path(File.dirname(output))
|
22
|
+
puts "Results will be saved into the directory #{@output_dir}"
|
23
|
+
@files_dir = File.join(@output_dir, "files")
|
24
|
+
if File.exists?(@output_dir)
|
25
|
+
archive_dir = File.join(@output_dir, "../archive")
|
26
|
+
FileUtils.mkdir_p(archive_dir) unless File.exists?(archive_dir)
|
27
|
+
FileUtils.mv @output_dir, File.join(archive_dir, "#{File.basename(@output_dir)}_#{File.mtime(@output_dir).strftime("%y%m%d_%H%M%S")}")
|
28
|
+
end
|
29
|
+
FileUtils.mkdir_p(@files_dir)
|
30
|
+
@files_saved_during_example = []
|
31
|
+
super
|
32
|
+
end
|
33
|
+
|
34
|
+
def example_started(example) # :nodoc:
|
35
|
+
@files_saved_during_example.clear
|
36
|
+
super
|
37
|
+
end
|
38
|
+
|
39
|
+
def extra_failure_content(failure) # :nodoc:
|
40
|
+
save_javascript_error
|
41
|
+
save_html
|
42
|
+
save_screenshot
|
43
|
+
|
44
|
+
content = []
|
45
|
+
content << "<span>"
|
46
|
+
@files_saved_during_example.each {|f| content << link_for(f)}
|
47
|
+
content << "</span>"
|
48
|
+
super + content.join($/)
|
49
|
+
end
|
50
|
+
|
51
|
+
def link_for(file) # :nodoc:
|
52
|
+
return unless File.exists?(file[:path])
|
53
|
+
|
54
|
+
description = file[:desc] ? file[:desc] : File.extname(file[:path]).upcase[1..-1]
|
55
|
+
path = Pathname.new(file[:path])
|
56
|
+
"<a href='#{path.relative_path_from(Pathname.new(@output_dir))}'>#{description}</a> "
|
57
|
+
end
|
58
|
+
|
59
|
+
def save_html # :nodoc:
|
60
|
+
begin
|
61
|
+
html = @browser.html
|
62
|
+
file_name = file_path("browser.html")
|
63
|
+
File.open(file_name, 'w') {|f| f.puts html}
|
64
|
+
rescue => e
|
65
|
+
$stderr.puts "saving of html failed: #{e.message}"
|
66
|
+
$stderr.puts e.backtrace
|
67
|
+
end
|
68
|
+
file_name
|
69
|
+
end
|
70
|
+
|
71
|
+
def save_screenshot(description="Screenshot", hwnd=@browser.hwnd) # :nodoc:
|
72
|
+
begin
|
73
|
+
@browser.bring_to_front
|
74
|
+
width, height, blob = Win32::Screenshot.capture_hwnd(hwnd)
|
75
|
+
file_name = file_path("screenshot.png", description)
|
76
|
+
img = Magick::ImageList.new
|
77
|
+
img.from_blob(blob)
|
78
|
+
img.write(file_name)
|
79
|
+
rescue => e
|
80
|
+
$stderr.puts "saving of screenshot failed: #{e.message}"
|
81
|
+
$stderr.puts e.backtrace
|
82
|
+
end
|
83
|
+
file_name
|
84
|
+
end
|
85
|
+
|
86
|
+
def save_javascript_error # :nodoc:
|
87
|
+
file_name = nil
|
88
|
+
begin
|
89
|
+
if @browser.is_a?(Watir::IE) && @browser.status =~ /Error on page/
|
90
|
+
autoit = Watir::autoit
|
91
|
+
autoit.AutoItSetOption("MouseCoordMode", 0)
|
92
|
+
autoit.ControlClick("[TITLE:#{@browser.title}]", "", "[CLASS:msctls_statusbar32]", "left", 2)
|
93
|
+
popup_title = "[REGEXPTITLE:^(Windows )?Internet Explorer$]"
|
94
|
+
autoit.WinWait(popup_title, "", 10)
|
95
|
+
file_name = save_screenshot("JS_Error", autoit.WinGetHandle(popup_title).hex)
|
96
|
+
autoit.WinClose(popup_title)
|
97
|
+
end
|
98
|
+
rescue => e
|
99
|
+
$stderr.puts "saving of javascript error failed: #{e.message}"
|
100
|
+
$stderr.puts e.backtrace
|
101
|
+
end
|
102
|
+
file_name
|
103
|
+
end
|
104
|
+
|
105
|
+
# Generates unique file name and path for each example.
|
106
|
+
#
|
107
|
+
# All file names generated with this method will be shown
|
108
|
+
# on the report.
|
109
|
+
def file_path(file_name, description=nil)
|
110
|
+
extension = File.extname(file_name)
|
111
|
+
basename = File.basename(file_name, extension)
|
112
|
+
file_path = File.join(@files_dir, "#{basename}_#{Time.now.strftime("%H%M%S")}_#{example_group_number}_#{example_number}#{extension}")
|
113
|
+
@files_saved_during_example.unshift(:desc => description, :path => file_path)
|
114
|
+
file_path
|
115
|
+
end
|
116
|
+
|
117
|
+
end
|
118
|
+
end
|
@@ -0,0 +1,97 @@
|
|
1
|
+
module WatirSplash
|
2
|
+
|
3
|
+
# WatirSplash runner class is responsible for:
|
4
|
+
# * generating directory structures for projects
|
5
|
+
# * starting RSpec with specified settings
|
6
|
+
class Runner
|
7
|
+
@@template_directory = File.join(File.dirname(__FILE__), "../../templates/")
|
8
|
+
|
9
|
+
class << self
|
10
|
+
|
11
|
+
# Run RSpec with custom settings
|
12
|
+
# * loads spec.opts from project's directory if exists
|
13
|
+
# * loads environment.rb from project's directory if exists
|
14
|
+
# * loads custom Formatter
|
15
|
+
def run
|
16
|
+
unless ARGV.empty?
|
17
|
+
require "watirsplash"
|
18
|
+
load_formatter
|
19
|
+
load_options
|
20
|
+
load_project_env
|
21
|
+
else
|
22
|
+
return help
|
23
|
+
end
|
24
|
+
|
25
|
+
::Spec::Runner::CommandLine.run
|
26
|
+
end
|
27
|
+
|
28
|
+
# Generates ui-test project structure for project
|
29
|
+
def generate
|
30
|
+
ui_test_dir = File.join(Dir.pwd, "ui-test")
|
31
|
+
puts "Creating WatirSplash project directory structure to #{ui_test_dir}..."
|
32
|
+
require "fileutils"
|
33
|
+
FileUtils.cp_r File.join(@@template_directory, "project/."), ui_test_dir
|
34
|
+
puts "Done"
|
35
|
+
return 0
|
36
|
+
rescue => e
|
37
|
+
puts "Failed:"
|
38
|
+
puts e.message
|
39
|
+
return -1
|
40
|
+
end
|
41
|
+
|
42
|
+
# Generates ui-test-common directory structure
|
43
|
+
def generate_common
|
44
|
+
common_dir = File.join(Dir.pwd, "ui-test-common")
|
45
|
+
puts "Creating WatirSplash common project directory structure to #{common_dir}..."
|
46
|
+
require "fileutils"
|
47
|
+
FileUtils.cp_r File.join(@@template_directory, "common/."), common_dir
|
48
|
+
puts "Done"
|
49
|
+
return 0
|
50
|
+
rescue => e
|
51
|
+
puts "Failed:"
|
52
|
+
puts e.message
|
53
|
+
return -1
|
54
|
+
end
|
55
|
+
|
56
|
+
# Shows help
|
57
|
+
def help
|
58
|
+
puts %Q{WatirSplash:
|
59
|
+
Usage: watirsplash (COMMAND|FILE(:LINE)?|DIRECTORY|GLOB)+ [options]
|
60
|
+
Commands:
|
61
|
+
* generate - generate default directory structure for new project
|
62
|
+
* generate_common - generate common project directory structure
|
63
|
+
* help - show this help
|
64
|
+
* --help - show RSpec's help
|
65
|
+
|
66
|
+
All other commands/options will be passed to RSpec directly.}
|
67
|
+
|
68
|
+
return 1
|
69
|
+
end
|
70
|
+
|
71
|
+
private
|
72
|
+
|
73
|
+
def load_formatter
|
74
|
+
ARGV << "--require" << "watirsplash/html_formatter.rb"
|
75
|
+
ARGV << "--format" << "WatirSplash::HtmlFormatter:#{File.join(Dir.pwd, "results/index.html")}"
|
76
|
+
end
|
77
|
+
|
78
|
+
def load_options
|
79
|
+
ARGV << "--options"
|
80
|
+
project_spec_opts = File.join(Dir.pwd, "spec.opts")
|
81
|
+
if File.exists?(project_spec_opts)
|
82
|
+
ARGV << project_spec_opts
|
83
|
+
else
|
84
|
+
ARGV << "#{File.join(File.dirname(__FILE__), "../spec.opts")}"
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
def load_project_env
|
89
|
+
project_env_file = File.join(Dir.pwd, "environment.rb")
|
90
|
+
if File.exists?(project_env_file)
|
91
|
+
ARGV << "--require" << project_env_file
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
end
|
96
|
+
end
|
97
|
+
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
Spec::Runner.configure do |config| #:nodoc:
|
2
|
+
config.include(WatirSplash::SpecHelper)
|
3
|
+
|
4
|
+
config.before(:all) do
|
5
|
+
open_browser_at "about:blank"
|
6
|
+
end
|
7
|
+
|
8
|
+
config.after(:all) do
|
9
|
+
close
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
module Spec #:nodoc:all
|
14
|
+
class ExampleGroup
|
15
|
+
subject {self}
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
# match_array is useful for matching arrays where some elements are regular expressions.
|
20
|
+
# expected_array = ["1", "2", /\d+/, "3"]
|
21
|
+
#
|
22
|
+
# ["1", "2", "66", "3"].should match_array(expected_array)
|
23
|
+
# table(:id => "table_id").to_a.should match_array(expected_array)
|
24
|
+
Spec::Matchers.define :match_array do |array2|
|
25
|
+
match do |array1|
|
26
|
+
raise "match_array works only with Array objects!" unless array1.is_a?(Array) && array2.is_a?(Array)
|
27
|
+
match?(array1, array2)
|
28
|
+
end
|
29
|
+
|
30
|
+
def match?(array1, array2)
|
31
|
+
array2.each_with_index do |element, i|
|
32
|
+
if element.is_a?(Array)
|
33
|
+
return false unless match?(array1[i], element)
|
34
|
+
elsif element.is_a?(Regexp)
|
35
|
+
return false unless array1[i] =~ element
|
36
|
+
else
|
37
|
+
return false unless array1[i] == element
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
true
|
42
|
+
end
|
43
|
+
end
|
@@ -0,0 +1,68 @@
|
|
1
|
+
module WatirSplash
|
2
|
+
# main helper module
|
3
|
+
#
|
4
|
+
# these methods can be used in specs directly
|
5
|
+
module SpecHelper
|
6
|
+
include Waiter
|
7
|
+
|
8
|
+
# opens the browser at specified url
|
9
|
+
def open_browser_at url
|
10
|
+
@browser = Watir::Browser.new
|
11
|
+
@browser.speed = :fast
|
12
|
+
add_checker Watir::PageCheckers::JAVASCRIPT_ERRORS_CHECKER
|
13
|
+
begin
|
14
|
+
formatter.browser = @browser
|
15
|
+
rescue
|
16
|
+
end
|
17
|
+
goto url
|
18
|
+
maximize
|
19
|
+
end
|
20
|
+
|
21
|
+
# downloads file with browser
|
22
|
+
#
|
23
|
+
# you need to use click_no_wait to use this method:
|
24
|
+
# button(:id => "something").click_no_wait # opens a browser save as dialog
|
25
|
+
# download_file("document.pdf")
|
26
|
+
#
|
27
|
+
# * raises an exception if saving the file is unsuccessful
|
28
|
+
# * returns absolute file_path of the saved file
|
29
|
+
def download_file file_name
|
30
|
+
AutoItHelper.click_save
|
31
|
+
file_path = native_file_path(file_path(file_name))
|
32
|
+
AutoItHelper.set_edit(file_path)
|
33
|
+
AutoItHelper.click_save("Save As")
|
34
|
+
wait_until! {File.exists?(file_path)}
|
35
|
+
file_path
|
36
|
+
end
|
37
|
+
|
38
|
+
# returns WatirSplash::HtmlFormatter object, nil if not in use
|
39
|
+
def formatter
|
40
|
+
@formatter ||= Spec::Runner.options.formatters.find {|f| f.kind_of?(WatirSplash::HtmlFormatter) rescue false}
|
41
|
+
end
|
42
|
+
|
43
|
+
# returns unique file path for use in examples.
|
44
|
+
#
|
45
|
+
# all file names generated with this method will
|
46
|
+
# be shown on the report upon test failure.
|
47
|
+
def file_path(file_name, description=nil)
|
48
|
+
formatter.file_path(file_name, description)
|
49
|
+
rescue
|
50
|
+
extension = File.extname(file_name)
|
51
|
+
basename = File.basename(file_name, extension)
|
52
|
+
file_path = File.join(Dir.pwd, "#{basename}_#{Time.now.strftime("%H%M%S")}#{extension}")
|
53
|
+
file_path
|
54
|
+
end
|
55
|
+
|
56
|
+
# returns native file path
|
57
|
+
# e.g. on Windows:
|
58
|
+
# native_file_path("c:/blah/blah2/file.txt") => c:\\blah\\blah2\\file.txt
|
59
|
+
def native_file_path(file_path)
|
60
|
+
File::ALT_SEPARATOR ? file_path.gsub(File::SEPARATOR, File::ALT_SEPARATOR) : file_path
|
61
|
+
end
|
62
|
+
|
63
|
+
def method_missing name, *arg #:nodoc:
|
64
|
+
@browser.respond_to?(name) ? @browser.send(name, *arg) : super
|
65
|
+
end
|
66
|
+
|
67
|
+
end
|
68
|
+
end
|