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