zfben_hanoi 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
data/.gitignore ADDED
@@ -0,0 +1,4 @@
1
+ *.gem
2
+ .bundle
3
+ Gemfile.lock
4
+ pkg/*
data/Gemfile ADDED
@@ -0,0 +1,7 @@
1
+ source "http://rubygems.org"
2
+
3
+ # Specify your gem's dependencies in zfben_hanoi.gemspec
4
+ gemspec
5
+
6
+ gem 'rspec'
7
+ gem 'mocha'
data/MIT-LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2009 - 2010 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.md ADDED
@@ -0,0 +1,105 @@
1
+ # Automated jQuery tests with QUnit
2
+
3
+ ## Installation
4
+
5
+ (sudo) gem install zfben_hanoi
6
+
7
+ ## Crash Course
8
+
9
+ zfben_hanoi # prepare the target directory
10
+ rake test:js # run the tests
11
+
12
+ ## 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
+ ## Structure
35
+
36
+ The `zfben_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 Rake file, **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](http://jquery.com) and [QUnit](http://docs.jquery.com/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
+ ## Browsers & Platforms
87
+
88
+ ### Platforms:
89
+
90
+ * Linux
91
+
92
+ ### Browsers:
93
+
94
+ * Chrome (Mac OS X and Windows)
95
+ * Firefox
96
+
97
+ ## Repository
98
+
99
+ git clone git://github.com/benz303/zfben_hanoi.git
100
+
101
+ ## Copyright
102
+
103
+ (c) [http://zfben.com](http://zfben.com), released under the MIT license
104
+
105
+ From [https://github.com/jodosha/hanoi](https://github.com/jodosha/hanoi)
data/Rakefile ADDED
@@ -0,0 +1,8 @@
1
+ require 'rubygems'
2
+ require 'bundler/gem_tasks'
3
+ require 'rspec/core/rake_task'
4
+
5
+ RSpec::Core::RakeTask.new(:test) do |t|
6
+ t.pattern = FileList['spec/**/*_spec.rb']
7
+ t.rspec_opts = %w(-fs --color)
8
+ 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
@@ -0,0 +1,65 @@
1
+ class Browser
2
+ def supported?; true; end
3
+ def setup; end
4
+ def teardown; end
5
+
6
+ def host
7
+ require 'rbconfig'
8
+ Config::CONFIG['host']
9
+ end
10
+
11
+ def macos?
12
+ host.include?('darwin')
13
+ end
14
+
15
+ def windows?
16
+ /mswin|mingw/.match host
17
+ end
18
+
19
+ def linux?
20
+ host.include?('linux')
21
+ end
22
+
23
+ def installed?
24
+ if linux?
25
+ Kernel.system "which #{name}"
26
+ else
27
+ File.exist? path
28
+ end
29
+ end
30
+
31
+ def runnable?
32
+ supported? && installed?
33
+ end
34
+
35
+ def visit(url)
36
+ if macos?
37
+ system("open -g -a #{path} '#{url}'")
38
+ elsif windows?
39
+ system("#{path} #{url}")
40
+ elsif linux?
41
+ system("#{name} #{url}")
42
+ end
43
+ end
44
+
45
+ def name
46
+ n = self.class.name.split('::').last
47
+ linux? ? n.downcase : n
48
+ end
49
+
50
+ def escaped_name
51
+ name.gsub(' ', '\ ')
52
+ end
53
+
54
+ def path
55
+ if macos?
56
+ File.expand_path("/Applications/#{escaped_name}.app")
57
+ else
58
+ @path
59
+ end
60
+ end
61
+
62
+ def to_s
63
+ name
64
+ end
65
+ end
@@ -0,0 +1,35 @@
1
+ class Chrome < Browser
2
+ def initialize(path = nil)
3
+ @path = path || File.join(
4
+ ENV['UserPath'] || ENV['UserProfile'] || "C:/Documents and Settings/Administrator",
5
+ "AppData",
6
+ "Local",
7
+ "Google",
8
+ "Chrome",
9
+ "Application",
10
+ "chrome.exe"
11
+ )
12
+ end
13
+
14
+ def supported?
15
+ windows? || macos?
16
+ end
17
+
18
+ def installed?
19
+ if macos?
20
+ File.exist?("/Applications/#{name}.app")
21
+ else
22
+ super
23
+ end
24
+ end
25
+
26
+ def name
27
+ "Google Chrome"
28
+ end
29
+
30
+ def teardown
31
+ if macos?
32
+ system("killall #{escaped_name}")
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,11 @@
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 teardown
7
+ if macos?
8
+ system("killall firefox-bin")
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,26 @@
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 runnable?
11
+ supported?
12
+ end
13
+
14
+ def visit(url)
15
+ if windows?
16
+ ie = WIN32OLE.new('InternetExplorer.Application')
17
+ ie.visible = true
18
+ ie.Navigate(url)
19
+ sleep 0.01 while ie.Busy || ie.ReadyState != 4
20
+ end
21
+ end
22
+
23
+ def name
24
+ "Internet Explorer"
25
+ end
26
+ end
@@ -0,0 +1,29 @@
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
+ end
@@ -0,0 +1,17 @@
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
+ end
@@ -0,0 +1,5 @@
1
+ class Safari < Webkit
2
+ def initialize(path = File.join(ENV['ProgramFiles'] || 'c:\Program Files', '\Safari\Safari.exe'))
3
+ @path = path
4
+ end
5
+ end
@@ -0,0 +1,35 @@
1
+ class Webkit < Browser
2
+ def initialize(path = File.join(ENV['WEBKIT_HOME'] || ENV['ProgramFiles'] || 'C:\Program Files', 'Webkit', 'webkit.exe'))
3
+ @path = path
4
+ end
5
+
6
+ def supported?
7
+ macos? || windows?
8
+ end
9
+
10
+ def setup
11
+ applescript(%(tell application "#{name}" to make new document)) if macos?
12
+ end
13
+
14
+ def visit(url)
15
+ if macos?
16
+ applescript(%(tell application "#{name}" to set URL of front document to "#{url}"))
17
+ elsif windows?
18
+ system("#{path} #{url}")
19
+ end
20
+ end
21
+
22
+ def teardown
23
+ #applescript('tell application "Safari" to close front document')
24
+
25
+ if macos?
26
+ system("killall #{escaped_name}")
27
+ end
28
+ end
29
+
30
+ private
31
+ def applescript(script)
32
+ raise "Can't run AppleScript on #{host}" unless macos?
33
+ system "osascript -e '#{script}' 2>&1 >/dev/null"
34
+ end
35
+ end
@@ -0,0 +1,202 @@
1
+ class JavaScriptTestTask < ::Rake::TaskLib
2
+ BROWSERS = %w( chrome safari firefox ie konqueror opera webkit ).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.runnable?
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 or not installed."
51
+ end
52
+ end
53
+
54
+ destroy_temp_directory
55
+ @server.shutdown
56
+ t.join
57
+
58
+ exit 1 if @test_suite_results.failure? || @test_suite_results.error?
59
+ end
60
+ end
61
+
62
+ def get_url(test)
63
+ params = "resultsURL=http://localhost:4711/results&t=" + ("%.6f" % Time.now.to_f)
64
+ params << "&tests=#{test[:testcases]}" unless test[:testcases] == :all
65
+ "http://localhost:4711#{test[:url]}?#{params}"
66
+ end
67
+
68
+ def setup(sources_directory, test_cases, browsers)
69
+ @sources_directory = sources_directory
70
+ test_cases = setup_tests(test_cases)
71
+ run_test_cases(test_cases)
72
+ setup_mount_paths
73
+ setup_browsers(browsers)
74
+ end
75
+
76
+ def mount(path, dir = nil)
77
+ dir = current_directory + path unless dir
78
+
79
+ # don't cache anything in our tests
80
+ @server.mount(path, NonCachingFileHandler, dir)
81
+ end
82
+
83
+ # test should be specified as a hash of the form
84
+ # {:url => "url", :testcases => "testFoo,testBar"}.
85
+ # specifying :testcases is optional
86
+ def run(url, testcases = :all)
87
+ @tests << { :url => url, :testcases => testcases }
88
+ end
89
+
90
+ def browser(browser)
91
+ browser =
92
+ case(browser)
93
+ when :chrome
94
+ Chrome.new
95
+ when :firefox
96
+ Firefox.new
97
+ when :safari
98
+ Safari.new
99
+ when :ie
100
+ InternetExplorer.new
101
+ when :konqueror
102
+ Konqueror.new
103
+ when :opera
104
+ Opera.new
105
+ when :webkit
106
+ Webkit.new
107
+ else
108
+ browser
109
+ end
110
+
111
+ @browsers << browser
112
+ end
113
+
114
+ protected
115
+ def setup_tests(test_cases)
116
+ create_temp_directory
117
+ test_cases ||= Dir["#{test_directory}/**/*_test.js"] + Dir["#{test_directory}/**/*_spec.js"]
118
+ test_cases.map do |test_case|
119
+ test_case = TestCase.new(test_case, test_directory)
120
+ unless test_case.exist?
121
+ destroy_temp_directory
122
+ raise "Test case not found: '#{test_case.path}'"
123
+ end
124
+ test_case.create_temp_directory
125
+ write_template test_case
126
+ test_case
127
+ end
128
+ end
129
+
130
+ def setup_mount_paths
131
+ mount "/", assets_directory
132
+ mount "/test", temp_directory
133
+ mount "/javascripts", sources_directory
134
+ end
135
+
136
+ def setup_browsers(browsers)
137
+ BROWSERS.each do |browser|
138
+ browser(browser.to_sym) unless browsers && !browsers.include?(browser)
139
+ end
140
+ end
141
+
142
+ def run_test_cases(test_cases)
143
+ test_cases.each { |test_case| run test_case.url }
144
+ end
145
+
146
+ def test_directory
147
+ @test_directory ||= begin
148
+ directory = File.directory?(File.expand_path(current_directory + "/test")) ? "test" : "spec"
149
+ directory << "/javascript"
150
+ unless File.directory?(directory)
151
+ raise <<-END
152
+ Can't find JavaScript test directory in '#{current_directory}'.
153
+ Please make sure at least one of them exist:
154
+ \t'#{current_directory}/test/javascript'
155
+ \t'#{current_directory}/spec/javascript'\n
156
+ END
157
+ end
158
+ directory
159
+ end
160
+ end
161
+
162
+ def template
163
+ @template ||= begin
164
+ path = File.expand_path(test_directory + "/templates/test_case.erb")
165
+ raise "Can't find the Javascript test template: '#{path}'" unless File.exist?(path)
166
+ ERB.new(File.new(path).read)
167
+ end
168
+ end
169
+
170
+ def write_template(test_case)
171
+ # instance var is needed by ERb binding.
172
+ @test_case = test_case
173
+ template_path = "#{test_case.temp_directory}/#{test_case.name}.html"
174
+ File.open(template_path, 'w') { |f| f.write(template.result(binding)) }
175
+ end
176
+
177
+ def current_directory
178
+ @current_directory ||= Dir.pwd
179
+ end
180
+
181
+ def create_temp_directory
182
+ FileUtils.mkdir_p temp_directory
183
+ end
184
+
185
+ def destroy_temp_directory
186
+ FileUtils.rm_rf(temp_directory) rescue nil
187
+ end
188
+
189
+ def temp_directory
190
+ @temp_directory ||= test_directory + "/tmp"
191
+ end
192
+
193
+ def assets_directory
194
+ @assets_directory ||= begin
195
+ path = File.expand_path(current_directory + "/test/javascript/assets")
196
+ return path if File.directory?(path)
197
+ path = File.expand_path(current_directory + "/spec/javascript/assets")
198
+ return path if File.directory?(path)
199
+ raise "Cannot find:\n\t#{File.expand_path(current_directory + "/test/javascript/assets")} or\n\t#{File.expand_path(current_directory + "/spec/javascript/assets")}"
200
+ end
201
+ end
202
+ end