hanoi 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/MIT-LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2009 Luca Guidi
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.textile ADDED
@@ -0,0 +1,114 @@
1
+ h1. Automated jQuery tests with QUnit
2
+
3
+ h2. Installation
4
+
5
+ (sudo) gem install jodosha-hanoi -s http://gems.github.com
6
+
7
+ h2. Crash Course
8
+
9
+ hanoi # prepare the target directory
10
+ rake test:js # run the tests
11
+
12
+ h2. How To Use
13
+
14
+ Prepare the target directory, you can use one of the following options:
15
+
16
+ hanoi
17
+ hanoi .
18
+ hanoi /path/to/project
19
+
20
+ You need a valid "Rake":http://rake.rubyforge.org/ installation to run your tests:
21
+
22
+ rake test:js
23
+
24
+ You can specify to run the test against one or more browsers:
25
+
26
+ rake test:js BROWSERS=firefox,ie,safari
27
+
28
+ You can specify to run only certain tests:
29
+
30
+ rake test:js TESTS=path/to/first_test.js,path/to/second_test.js
31
+
32
+ You can combine both @BROWSERS@ and @TESTS@ configurations.
33
+
34
+ h2. Structure
35
+
36
+ The @hanoi@ executable will create the following structure:
37
+
38
+ Rakefile
39
+ test/
40
+ javascript/
41
+ assets/
42
+ jquery.js
43
+ testrunner.js
44
+ testsuite.css
45
+ example_test.js
46
+ fixtures/
47
+ example_fixtures.html
48
+ templates/
49
+ test_case.erb
50
+
51
+ * @Rakefile@ creates a fresh rakefile, *you have to edit* it according to your setup
52
+ * @test@ Hanoi creates it if missing, otherwise will choose between existing @test@ or @spec@ paths
53
+ * @javascript@ is the root directory of your tests
54
+ * @assets@ contains the jQuery and QUnit source file and a css.
55
+ Place your assets in this directory, it's mapped as root path @/@.
56
+ * @example_test.js@ is a sample of a real test case.
57
+ * @templates@ contains the template file for your tests. You shouldn't edit it, if you don't know the risk.
58
+ * @fixtures@ contains all the HTML fixtures, each file will be injected into the proper case.
59
+
60
+ By convention, your @test/javascript@ folder *should reflect* the structure of your source directory,
61
+ appending the @_test.js@ suffix to each test case and the @_fixtures.html@ to each fixture file.
62
+
63
+ Example:
64
+
65
+ src/
66
+ directory_a/
67
+ directory_b/
68
+ file_3.js
69
+ file_2.js
70
+ file_1.js
71
+ test/
72
+ javascript/
73
+ directory_a/
74
+ directory_b/
75
+ file_3_test.js
76
+ file_2_test.js
77
+ file_1_test.js
78
+ fixtures/
79
+ directory_a/
80
+ directory_b/
81
+ file_3_fixtures.html
82
+ file_1_fixtures.html
83
+
84
+ You have probably noticed that @file_2_fixtures.html@ is missing, this because *fixtures are optional*.
85
+
86
+ h2. Browsers & Platforms
87
+
88
+ h3. Platforms:
89
+
90
+ * MacOS
91
+ * Windows
92
+ * Linux
93
+
94
+ h3. Browsers:
95
+
96
+ * Firefox
97
+ * Safari
98
+ * Internet Explorer
99
+ * Opera
100
+ * Konqueror
101
+
102
+ h2. Acknowledgements
103
+
104
+ The Ruby libraries of Hanoi are a customization of the jsblib.rb, courtesy of the "Prototype":http://prototypejs.org team.
105
+
106
+ Hanoi runs a customized version of QUnit, courtesy of the "jQuery":http://jquery.com team.
107
+
108
+ h2. Repository
109
+
110
+ git clone git://github.com/jodosha/hanoi.git
111
+
112
+ h2. Copyright
113
+
114
+ (c) 2009 Luca Guidi - "http://lucaguidi.com":http://lucaguidi.com, released under the MIT license
data/Rakefile ADDED
@@ -0,0 +1,29 @@
1
+ $:.unshift 'lib'
2
+ require 'rubygems'
3
+ require 'rake'
4
+ require 'rake/testtask'
5
+ require 'rake/rdoctask'
6
+ require 'spec/rake/spectask'
7
+
8
+ HANOI_VERSION = "0.0.1"
9
+
10
+ task :default => :spec
11
+
12
+ desc 'Build and install the gem (useful for development purposes).'
13
+ task :install do
14
+ system "gem build hanoi.gemspec"
15
+ system "sudo gem uninstall hanoi"
16
+ system "sudo gem install --local --no-rdoc --no-ri hanoi-#{HANOI_VERSION}.gem"
17
+ system "rm hanoi-*.gem"
18
+ end
19
+
20
+ Spec::Rake::SpecTask.new do |t|
21
+ t.spec_files = FileList['spec/**/*_spec.rb']
22
+ t.spec_opts = %w(-fs --color)
23
+ end
24
+
25
+ desc 'Show the file list for the gemspec file'
26
+ task :files do
27
+ puts "Files:\n #{Dir['**/*'].reject {|f| File.directory?(f)}.sort.inspect}"
28
+ puts "Test files:\n #{Dir['spec/**/*_spec.rb'].reject {|f| File.directory?(f)}.sort.inspect}"
29
+ end
data/bin/hanoi ADDED
@@ -0,0 +1,26 @@
1
+ #!/usr/bin/env ruby
2
+ require "fileutils"
3
+
4
+ path = ARGV[0] || Dir.pwd
5
+ raise "Unknown path '#{path}'" unless File.directory?(path)
6
+ templates_path = File.expand_path(File.dirname(__FILE__) + "/../templates")
7
+
8
+ # Rakefile
9
+ File.open(File.join(path, "Rakefile"), "a") { |f| f.write(File.readlines(File.join(templates_path, "fresh_rakefile")))}
10
+
11
+ # JavaScript test directory
12
+ name = File.directory?(File.join(path, "spec")) ? "spec" : "test"
13
+ path = File.join(path, name, "javascript")
14
+ FileUtils.mkdir_p path
15
+
16
+ # Assets
17
+ FileUtils.cp_r File.join(templates_path, "assets"), File.join(path)
18
+
19
+ # Template
20
+ FileUtils.mkdir_p File.join(path, "templates")
21
+ FileUtils.cp File.join(templates_path, "test_case.erb"), File.join(path, "templates")
22
+
23
+ # Samples
24
+ FileUtils.mkdir_p File.join(path, "fixtures")
25
+ FileUtils.cp File.join(templates_path, "example_fixtures.html"), File.join(path, "fixtures")
26
+ FileUtils.cp File.join(templates_path, "example_test.js"), path
data/hanoi.gemspec ADDED
@@ -0,0 +1,14 @@
1
+ Gem::Specification.new do |s|
2
+ s.name = "hanoi"
3
+ s.version = "0.0.1"
4
+ s.date = "2009-06-09"
5
+ s.summary = "Automated jQuery tests with QUnit"
6
+ s.author = "Luca Guidi"
7
+ s.email = "guidi.luca@gmail.com"
8
+ s.description = "Automated jQuery tests with QUnit"
9
+ s.has_rdoc = true
10
+ s.executables = [ 'hanoi' ]
11
+ s.files = ["MIT-LICENSE", "README.textile", "Rakefile", "bin/hanoi", "hanoi.gemspec", "lib/hanoi.rb", "lib/hanoi/browser.rb", "lib/hanoi/browsers/firefox.rb", "lib/hanoi/browsers/internet_explorer.rb", "lib/hanoi/browsers/konqueror.rb", "lib/hanoi/browsers/opera.rb", "lib/hanoi/browsers/safari.rb", "lib/hanoi/javascript_test_task.rb", "lib/hanoi/test_case.rb", "lib/hanoi/test_results.rb", "lib/hanoi/test_suite_results.rb", "lib/hanoi/webrick.rb", "spec/browser_spec.rb", "spec/browsers/firefox_spec.rb", "spec/browsers/internet_explorer_spec.rb", "spec/browsers/konqueror_spec.rb", "spec/browsers/opera_spec.rb", "spec/browsers/safari_spec.rb", "spec/spec_helper.rb", "templates/assets/jquery.js", "templates/assets/testrunner.js", "templates/assets/testsuite.css", "templates/example_fixtures.html", "templates/example_test.js", "templates/fresh_rakefile", "templates/test_case.erb"]
12
+ s.test_files = ["spec/browser_spec.rb", "spec/browsers/firefox_spec.rb", "spec/browsers/internet_explorer_spec.rb", "spec/browsers/konqueror_spec.rb", "spec/browsers/opera_spec.rb", "spec/browsers/safari_spec.rb"]
13
+ s.extra_rdoc_files = ['README.textile']
14
+ end
data/lib/hanoi.rb ADDED
@@ -0,0 +1,14 @@
1
+ require "erb"
2
+ require "webrick"
3
+ require "rake/tasklib"
4
+ require "hanoi/webrick"
5
+ require "hanoi/browser"
6
+ require "hanoi/browsers/firefox"
7
+ require "hanoi/browsers/internet_explorer"
8
+ require "hanoi/browsers/konqueror"
9
+ require "hanoi/browsers/safari"
10
+ require "hanoi/browsers/opera"
11
+ require "hanoi/test_case"
12
+ require "hanoi/test_results"
13
+ require "hanoi/test_suite_results"
14
+ require "hanoi/javascript_test_task"
@@ -0,0 +1,28 @@
1
+ class Browser
2
+ def supported?; true; end
3
+ def setup ; end
4
+ def open(url) ; end
5
+ def teardown ; end
6
+
7
+ def host
8
+ require 'rbconfig'
9
+ Config::CONFIG['host']
10
+ end
11
+
12
+ def macos?
13
+ host.include?('darwin')
14
+ end
15
+
16
+ def windows?
17
+ host.include?('mswin')
18
+ end
19
+
20
+ def linux?
21
+ host.include?('linux')
22
+ end
23
+
24
+ def applescript(script)
25
+ raise "Can't run AppleScript on #{host}" unless macos?
26
+ system "osascript -e '#{script}' 2>&1 >/dev/null"
27
+ end
28
+ end
@@ -0,0 +1,15 @@
1
+ class Firefox < Browser
2
+ def initialize(path = File.join(ENV['ProgramFiles'] || 'c:\Program Files', '\Mozilla Firefox\firefox.exe'))
3
+ @path = path
4
+ end
5
+
6
+ def visit(url)
7
+ system("open -a Firefox '#{url}'") if macos?
8
+ system("#{@path} #{url}") if windows?
9
+ system("firefox #{url}") if linux?
10
+ end
11
+
12
+ def to_s
13
+ "Firefox"
14
+ end
15
+ end
@@ -0,0 +1,22 @@
1
+ class InternetExplorer < Browser
2
+ def setup
3
+ require 'win32ole' if windows?
4
+ end
5
+
6
+ def supported?
7
+ windows?
8
+ end
9
+
10
+ def visit(url)
11
+ if windows?
12
+ ie = WIN32OLE.new('InternetExplorer.Application')
13
+ ie.visible = true
14
+ ie.Navigate(url)
15
+ sleep 0.01 while ie.Busy || ie.ReadyState != 4
16
+ end
17
+ end
18
+
19
+ def to_s
20
+ "Internet Explorer"
21
+ end
22
+ end
@@ -0,0 +1,37 @@
1
+ class Konqueror < Browser
2
+ @@config_dir = File.join((ENV['HOME'] || ''), '.kde', 'share', 'config')
3
+ @@global_config = File.join(@@config_dir, 'kdeglobals')
4
+ @@konqueror_config = File.join(@@config_dir, 'konquerorrc')
5
+
6
+ def supported?
7
+ linux?
8
+ end
9
+
10
+ # Forces KDE's default browser to be Konqueror during the tests, and forces
11
+ # Konqueror to open external URL requests in new tabs instead of a new
12
+ # window.
13
+ def setup
14
+ cd @@config_dir, :verbose => false do
15
+ copy @@global_config, "#{@@global_config}.bak", :preserve => true, :verbose => false
16
+ copy @@konqueror_config, "#{@@konqueror_config}.bak", :preserve => true, :verbose => false
17
+ # Too lazy to write it in Ruby... Is sed dependency so bad?
18
+ system "sed -ri /^BrowserApplication=/d '#{@@global_config}'"
19
+ system "sed -ri /^KonquerorTabforExternalURL=/s:false:true: '#{@@konqueror_config}'"
20
+ end
21
+ end
22
+
23
+ def teardown
24
+ cd @@config_dir, :verbose => false do
25
+ copy "#{@@global_config}.bak", @@global_config, :preserve => true, :verbose => false
26
+ copy "#{@@konqueror_config}.bak", @@konqueror_config, :preserve => true, :verbose => false
27
+ end
28
+ end
29
+
30
+ def visit(url)
31
+ system("kfmclient openURL #{url}")
32
+ end
33
+
34
+ def to_s
35
+ "Konqueror"
36
+ end
37
+ end
@@ -0,0 +1,27 @@
1
+ class Opera < Browser
2
+ def initialize(path = 'c:\Program Files\Opera\Opera.exe')
3
+ @path = path
4
+ end
5
+
6
+ def setup
7
+ if windows?
8
+ puts %{
9
+ MAJOR ANNOYANCE on Windows.
10
+ You have to shut down Opera manually after each test
11
+ for the script to proceed.
12
+ Any suggestions on fixing this is GREATLY appreciated!
13
+ Thank you for your understanding.
14
+ }
15
+ end
16
+ end
17
+
18
+ def visit(url)
19
+ applescript('tell application "Opera" to GetURL "' + url + '"') if macos?
20
+ system("#{@path} #{url}") if windows?
21
+ system("opera #{url}") if linux?
22
+ end
23
+
24
+ def to_s
25
+ "Opera"
26
+ end
27
+ end
@@ -0,0 +1,21 @@
1
+ class Safari < Browser
2
+ def supported?
3
+ macos? || windows?
4
+ end
5
+
6
+ def setup
7
+ applescript('tell application "Safari" to make new document')
8
+ end
9
+
10
+ def visit(url)
11
+ applescript('tell application "Safari" to set URL of front document to "' + url + '"')
12
+ end
13
+
14
+ def teardown
15
+ #applescript('tell application "Safari" to close front document')
16
+ end
17
+
18
+ def to_s
19
+ "Safari"
20
+ end
21
+ end
@@ -0,0 +1,190 @@
1
+ class JavaScriptTestTask < ::Rake::TaskLib
2
+ BROWSERS = %w( safari firefox ie konqueror opera ).freeze
3
+ attr_reader :sources_directory
4
+
5
+ def initialize(name = :test)
6
+ @name = name
7
+ @tests = []
8
+ @browsers = []
9
+
10
+ @queue = Queue.new
11
+
12
+ @server = WEBrick::HTTPServer.new(:Port => 4711) # TODO: make port configurable
13
+ @server.mount_proc("/results") do |req, res|
14
+ @queue.push(req)
15
+ res.body = "OK"
16
+ end
17
+ @server.mount("/response", BasicServlet)
18
+ @server.mount("/slow", SlowServlet)
19
+ @server.mount("/down", DownServlet)
20
+ @server.mount("/inspect", InspectionServlet)
21
+ yield self if block_given?
22
+ define
23
+ end
24
+
25
+ def define
26
+ task @name do
27
+ trap("INT") { @server.shutdown; exit }
28
+ t = Thread.new { @server.start }
29
+
30
+ # run all combinations of browsers and tests
31
+ @browsers.each do |browser|
32
+ if browser.supported?
33
+ t0 = Time.now
34
+ test_suite_results = TestSuiteResults.new
35
+
36
+ browser.setup
37
+ puts "\nStarted tests in #{browser}."
38
+
39
+ @tests.each do |test|
40
+ browser.visit(get_url(test))
41
+ results = TestResults.new(@queue.pop.query, test[:url])
42
+ print results
43
+ test_suite_results << results
44
+ end
45
+
46
+ print "\nFinished in #{Time.now - t0} seconds."
47
+ print test_suite_results
48
+ browser.teardown
49
+ else
50
+ puts "\nSkipping #{browser}, not supported on this OS."
51
+ end
52
+ end
53
+
54
+ destroy_temp_directory
55
+ @server.shutdown
56
+ t.join
57
+ end
58
+ end
59
+
60
+ def get_url(test)
61
+ params = "resultsURL=http://localhost:4711/results&t=" + ("%.6f" % Time.now.to_f)
62
+ params << "&tests=#{test[:testcases]}" unless test[:testcases] == :all
63
+ "http://localhost:4711#{test[:url]}?#{params}"
64
+ end
65
+
66
+ def setup(sources_directory, test_cases, browsers)
67
+ @sources_directory = sources_directory
68
+ test_cases = setup_tests(test_cases)
69
+ run_test_cases(test_cases)
70
+ setup_mount_paths
71
+ setup_browsers(browsers)
72
+ end
73
+
74
+ def mount(path, dir = nil)
75
+ dir = current_directory + path unless dir
76
+
77
+ # don't cache anything in our tests
78
+ @server.mount(path, NonCachingFileHandler, dir)
79
+ end
80
+
81
+ # test should be specified as a hash of the form
82
+ # {:url => "url", :testcases => "testFoo,testBar"}.
83
+ # specifying :testcases is optional
84
+ def run(url, testcases = :all)
85
+ @tests << { :url => url, :testcases => testcases }
86
+ end
87
+
88
+ def browser(browser)
89
+ browser =
90
+ case(browser)
91
+ when :firefox
92
+ Firefox.new
93
+ when :safari
94
+ Safari.new
95
+ when :ie
96
+ InternetExplorer.new
97
+ when :konqueror
98
+ Konqueror.new
99
+ when :opera
100
+ Opera.new
101
+ else
102
+ browser
103
+ end
104
+
105
+ @browsers << browser
106
+ end
107
+
108
+ protected
109
+ def setup_tests(test_cases)
110
+ create_temp_directory
111
+ test_cases ||= Dir["#{test_directory}/**/*_test.js"] + Dir["#{test_directory}/**/*_spec.js"]
112
+ test_cases.map do |test_case|
113
+ test_case = TestCase.new(test_case, test_directory)
114
+ unless test_case.exist?
115
+ destroy_temp_directory
116
+ raise "Test case not found: '#{test_case.path}'"
117
+ end
118
+ test_case.create_temp_directory
119
+ write_template test_case
120
+ test_case
121
+ end
122
+ end
123
+
124
+ def setup_mount_paths
125
+ mount "/", assets_directory
126
+ mount "/test", temp_directory
127
+ mount "/javascripts", sources_directory
128
+ end
129
+
130
+ def setup_browsers(browsers)
131
+ BROWSERS.each do |browser|
132
+ browser(browser.to_sym) unless browsers && !browsers.include?(browser)
133
+ end
134
+ end
135
+
136
+ def run_test_cases(test_cases)
137
+ test_cases.each { |test_case| run test_case.url }
138
+ end
139
+
140
+ def test_directory
141
+ @test_directory ||= begin
142
+ directory = File.directory?(File.expand_path(current_directory + "/test")) ? "test" : "spec"
143
+ directory << "/javascript"
144
+ unless File.directory?(directory)
145
+ raise <<-END
146
+ Can't find JavaScript test directory in '#{current_directory}'.
147
+ Please make sure at least one of them exist:
148
+ \t'#{current_directory}/test/javascript'
149
+ \t'#{current_directory}/spec/javascript'\n
150
+ END
151
+ end
152
+ directory
153
+ end
154
+ end
155
+
156
+ def template
157
+ @template ||= begin
158
+ path = File.expand_path(test_directory + "/templates/test_case.erb")
159
+ raise "Can't find the Javascript test template: '#{path}'" unless File.exist?(path)
160
+ ERB.new(File.new(path).read)
161
+ end
162
+ end
163
+
164
+ def write_template(test_case)
165
+ # instance var is needed by ERb binding.
166
+ @test_case = test_case
167
+ template_path = "#{test_case.temp_directory}/#{test_case.name}.html"
168
+ File.open(template_path, 'w') { |f| f.write(template.result(binding)) }
169
+ end
170
+
171
+ def current_directory
172
+ @current_directory ||= Dir.pwd
173
+ end
174
+
175
+ def create_temp_directory
176
+ FileUtils.mkdir_p temp_directory
177
+ end
178
+
179
+ def destroy_temp_directory
180
+ FileUtils.rm_rf(temp_directory) rescue nil
181
+ end
182
+
183
+ def temp_directory
184
+ @temp_directory ||= test_directory + "/tmp"
185
+ end
186
+
187
+ def assets_directory
188
+ @assets_directory ||= File.expand_path(current_directory + "/test/javascript/assets").freeze
189
+ end
190
+ end