nakajima-screw-driver 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
data/README.textile ADDED
@@ -0,0 +1,58 @@
1
+ h1. Screw.Driver
2
+
3
+ Another way to run your Screw.Unit tests.
4
+
5
+ h3. INSTALL
6
+
7
+ To build the gem, run this:
8
+
9
+ gemify -I
10
+
11
+ "View the CI build":http://ci.patnakajima.com/screw-driver
12
+
13
+ h3. ABOUT
14
+
15
+ Still really early. To try it, run this:
16
+
17
+ ./bin/screwdriver spec/fixtures/suite.html
18
+
19
+ You can specify a browser like so:
20
+
21
+ screwdriver spec/fixtures/suite.html --browser Safari
22
+
23
+ By default, Screw.Driver uses Firefox.
24
+
25
+ If you don't want the server to automatically quit after
26
+ your suite runs, you can use the "--server" option:
27
+
28
+ screwdriver spec/fixtures/suite.html --server
29
+
30
+ Screw.Driver will generate urls for each of the external
31
+ scripts and CSS links you include in your suite.html file,
32
+ and will serve them from the directory that contains the
33
+ suite.html file.
34
+
35
+ To specify additional load paths for your JavaScripts, you can
36
+ use the "--load-paths" option:
37
+
38
+ screwdriver spec/fixtures/suite.html --load-paths src/
39
+
40
+ h3. Using with Rails
41
+
42
+ If you're using Rails, run screwdriver from the root directory
43
+ of your app, and specify the "--rails" option. This will cause
44
+ the Screw.Driver server to serve the JavaScript files in your
45
+ public/javascripts directory. Example:
46
+
47
+ screwdriver spec/fixtures/suite.html --rails
48
+
49
+ REQUIREMENTS
50
+ - sinatra
51
+ - hpricot
52
+ - gemify (to build)
53
+
54
+ TODO
55
+ - Inject base tag into DOM at Hpricot parsing stage
56
+ - Convert script src attributes to absolute paths at Hpricot parsing stage
57
+ - Don't kill all Firefox tabs when complete
58
+ - Use #load_paths for Rails functionality
data/Rakefile ADDED
@@ -0,0 +1,13 @@
1
+ require 'spec/rake/spectask'
2
+
3
+ task :default => [:spec]
4
+
5
+ desc "Run all specs"
6
+ Spec::Rake::SpecTask.new('spec') do |t|
7
+ t.spec_files = FileList['spec/**/*.rb']
8
+ end
9
+
10
+ task :run do
11
+ dir = File.dirname(__FILE__)
12
+ system "#{dir}/bin/screwdriver #{dir}/spec/fixtures/suite.html"
13
+ end
data/bin/screwdriver ADDED
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ $:.unshift File.join(File.dirname(__FILE__), '..', 'lib')
4
+
5
+ ARGS = ARGV.dup unless defined?(ARGS)
6
+ ARGV.clear
7
+
8
+ load 'server.rb'
@@ -0,0 +1,59 @@
1
+ // AjaxQueue - by Pat Nakajima
2
+ (function($) {
3
+ var startNextRequest = function() {
4
+ if ($.ajaxQueue.currentRequest) { return; }
5
+ if (request = $.ajaxQueue.queue.shift()) {
6
+ $.ajaxQueue.currentRequest = request;
7
+ request.perform();
8
+ }
9
+ }
10
+
11
+ var Request = function(url, type, options) {
12
+ this.opts = options || { };
13
+ this.opts.url = url;
14
+ this.opts.type = type;
15
+ var oldComplete = this.opts.complete || function() { }
16
+ this.opts.complete = function(response) {
17
+ oldComplete(response);
18
+ $.ajaxQueue.currentRequest = null;
19
+ startNextRequest();
20
+ };
21
+ }
22
+
23
+ Request.prototype.perform = function() {
24
+ $.ajax(this.opts);
25
+ }
26
+
27
+ var addRequest = function(url, type, options) {
28
+ var request = new Request(url, type, options);
29
+ $.ajaxQueue.queue.push(request);
30
+ startNextRequest();
31
+ }
32
+
33
+ $.ajaxQueue = {
34
+ queue: [],
35
+
36
+ currentRequest: null,
37
+
38
+ reset: function() {
39
+ $.ajaxQueue.queue = [];
40
+ $.ajaxQueue.currentRequest = null;
41
+ },
42
+
43
+ post: function(url, options) {
44
+ addRequest(url, 'POST', options);
45
+ },
46
+
47
+ get: function(url, options) {
48
+ addRequest(url, 'GET', options);
49
+ },
50
+
51
+ put: function(url, options) {
52
+ addRequest(url, 'PUT', options);
53
+ },
54
+
55
+ "delete": function(url, options) {
56
+ addRequest(url, 'DELETE', options);
57
+ }
58
+ }
59
+ })(jQuery)
@@ -0,0 +1,32 @@
1
+ (function($) {
2
+ $(Screw).bind('before', function() {
3
+ $.ajaxQueue.post('/before');
4
+ });
5
+
6
+ $(Screw).bind('after', function() {
7
+ $.ajaxQueue.post('/after');
8
+ $.ajaxQueue.post('/exit');
9
+ });
10
+
11
+ $(Screw).bind('loaded', function() {
12
+ $('.it').bind('passed', function(e) {
13
+ $.ajaxQueue.post('/passed');
14
+ });
15
+
16
+ $('.it').bind('failed', function(e, reason) {
17
+ var specName = $(this).find('h2').text();
18
+
19
+ // ERROR
20
+ if (reason.fileName || reason.lineNumber || reason.line) {
21
+ return $.ajaxQueue.post('/errored', {
22
+ data: { name: specName, reason: reason }
23
+ });
24
+ }
25
+
26
+ // FAILURE
27
+ $.ajaxQueue.post('/failed', {
28
+ data: { name: specName, reason: reason }
29
+ });
30
+ });
31
+ });
32
+ })(jQuery);
data/lib/browser.rb ADDED
@@ -0,0 +1,6 @@
1
+ module Screw
2
+ module Driver
3
+ module Browser
4
+ end
5
+ end
6
+ end
@@ -0,0 +1,21 @@
1
+ module Screw
2
+ module Driver
3
+ module Browser
4
+ class Firefox
5
+ def start
6
+ Thread.new do
7
+ sleep 1
8
+ system "open -a Firefox 'http://localhost:4567/?body%20%3E%20.describe'"
9
+ end
10
+ end
11
+
12
+ def kill
13
+ puts " killing Firefox... "
14
+ browser_pid = `ps aux | grep -v grep | grep Firefox.app`.scan(/\d+/).first
15
+ system("kill -s SIGTERM #{browser_pid}")
16
+ puts ' done.'
17
+ end
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,19 @@
1
+ module Screw
2
+ module Driver
3
+ module Browser
4
+ class Safari
5
+ def start
6
+ Thread.new { sleep 1; system "open -n -a Safari 'http://localhost:4567/?body%20%3E%20.describe'" }
7
+ # t.join
8
+ end
9
+
10
+ def kill
11
+ puts " killing Safari... "
12
+ browser_pid = `ps aux | grep -v grep | grep Safari.app`.scan(/\d+/).first
13
+ system("kill -s SIGTERM #{browser_pid}")
14
+ puts ' done.'
15
+ end
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,7 @@
1
+ module Hpricot
2
+ module Traverse
3
+ def insert_js(position, name)
4
+ send(position, %(<script src="/#{name}"> </script>))
5
+ end
6
+ end
7
+ end
data/lib/ext/string.rb ADDED
@@ -0,0 +1,13 @@
1
+ class String
2
+ def green
3
+ "\e[32m#{self}\e[0m"
4
+ end
5
+
6
+ def red
7
+ "\e[31m#{self}\e[0m"
8
+ end
9
+
10
+ def magenta
11
+ "\e[35m#{self}\e[0m"
12
+ end
13
+ end
data/lib/helpers.rb ADDED
@@ -0,0 +1,42 @@
1
+ helpers do
2
+ def padded(spaces=1)
3
+ spaces.times { puts "" }
4
+ yield
5
+ spaces.times { puts "" }
6
+ :ok
7
+ end
8
+
9
+ def report(str, params=nil)
10
+ params ? SUITE.failed!(params) : SUITE.passed!
11
+ SUITE.write_dot!(str)
12
+ sleep 0.1
13
+ :ok
14
+ end
15
+
16
+ def before_suite
17
+ SUITE.reset!
18
+ padded do
19
+ puts "Staring to run test suite..."
20
+ end
21
+ end
22
+
23
+ def after_suite
24
+ padded do
25
+ SUITE.failures.each do |failure|
26
+ padded do
27
+ puts "Failure:".red
28
+ puts "- #{failure[:name]}: #{failure[:reason]}"
29
+ end
30
+ end
31
+ print "Finished. #{SUITE.test_count} tests. "
32
+ print "#{SUITE.failures.length} failures." unless SUITE.failures.empty?
33
+ end
34
+ end
35
+
36
+ def exit_suite
37
+ padded do
38
+ puts "== Spec Server Exiting..."
39
+ SUITE.exit
40
+ end
41
+ end
42
+ end
data/lib/rails.rb ADDED
@@ -0,0 +1,25 @@
1
+ module Screw
2
+ module Driver
3
+ module Rails
4
+ def rails?
5
+ @rails
6
+ end
7
+
8
+ def rails_urls
9
+ @rails_urls ||= Dir[File.join(public_path, "**", "*.js")]
10
+ end
11
+
12
+ def generate_rails_urls
13
+ rails_urls.each do |url|
14
+ generate "/javascripts/#{File.basename(url)}", 'text/javascript', public_path
15
+ end
16
+ end
17
+
18
+ private
19
+
20
+ def public_path
21
+ @public_path ||= File.join(Dir.pwd, 'public', 'javascripts')
22
+ end
23
+ end
24
+ end
25
+ end
data/lib/server.rb ADDED
@@ -0,0 +1,26 @@
1
+ require 'rubygems'
2
+ require 'sinatra'
3
+ require 'ext/string.rb'
4
+ require 'ext/hpricot.rb'
5
+ require 'browser.rb'
6
+ require 'browsers/firefox.rb'
7
+ require 'browsers/safari.rb'
8
+ require 'rails.rb'
9
+ require 'suite.rb'
10
+ require 'helpers.rb'
11
+
12
+ configure do
13
+ Rack::CommonLogger.class_eval { def <<(str) end } # Inhibit logging retardase
14
+ SUITE = Screw::Driver::Suite.new(self, ARGS)
15
+ SUITE.browser.start
16
+ end
17
+
18
+ SUITE.generate_urls
19
+
20
+ get('/') { SUITE.to_s }
21
+ post('/passed') { report '.'.green }
22
+ post('/failed') { report 'F'.red, params }
23
+ post('/errored') { report 'E'.magenta, params }
24
+ post('/before') { before_suite }
25
+ post('/after') { after_suite }
26
+ post('/exit') { exit_suite unless SUITE.server? }
data/lib/suite.rb ADDED
@@ -0,0 +1,182 @@
1
+ require 'hpricot'
2
+ require 'optparse'
3
+ require 'ostruct'
4
+
5
+ module Screw
6
+ module Driver
7
+ class Suite
8
+ include Rails
9
+
10
+ attr_reader :failures, :test_count, :path, :load_paths, :context
11
+
12
+ def initialize(context, args)
13
+ @context = context
14
+ parse_args(args)
15
+ reset!
16
+ end
17
+
18
+ def passed!
19
+ @test_count += 1
20
+ end
21
+
22
+ def failed!(result)
23
+ @test_count += 1
24
+ @failures << result
25
+ end
26
+
27
+ def reset!
28
+ @test_count = 0
29
+ @failures = []
30
+ end
31
+
32
+ def working_directory
33
+ File.dirname(@path)
34
+ end
35
+
36
+ def generate_urls
37
+ generate_js_urls
38
+ generate_css_urls
39
+ generate_rails_urls if rails?
40
+ generate_fixture_urls if fixtures?
41
+ end
42
+
43
+ def script_urls
44
+ doc.search('script').map { |script| script['src'] }.compact
45
+ end
46
+
47
+ def link_urls
48
+ doc.search('link').map { |script| script['href'] }.compact
49
+ end
50
+
51
+ def to_s
52
+ doc.to_html
53
+ end
54
+
55
+ def browser
56
+ @browser
57
+ end
58
+
59
+ def server?
60
+ @server
61
+ end
62
+
63
+ def fixtures?
64
+ File.exists?(File.join(working_directory, 'fixtures'))
65
+ end
66
+
67
+ def exit
68
+ browser.kill
69
+ exit! failures.empty? ? 0 : 1
70
+ end
71
+
72
+ def write_dot!(str)
73
+ $stdout.print(str)
74
+ $stdout.flush
75
+ end
76
+
77
+ private
78
+
79
+ def generate_fixture_urls
80
+ Dir[File.join(working_directory, "fixtures", "*.html")].each do |fixture|
81
+ generate(File.join("fixtures", File.basename(fixture)), "text/html")
82
+ end
83
+ end
84
+
85
+ def generate_js_urls
86
+ script_urls.each do |url|
87
+ generate(url, "text/javascript")
88
+ end
89
+ end
90
+
91
+ def generate_css_urls
92
+ link_urls.each do |url|
93
+ generate(url, "text/css")
94
+ end
95
+ end
96
+
97
+ # i know. this is hideous.
98
+ def absolutize_url(url)
99
+ # file_path = File.expand_path(File.join(working_directory, url))
100
+ # full_path = File.expand_path(File.join(path, url))
101
+ # full_path.gsub(File.expand_path(path), '')
102
+ ('/' + url.split('./').last).gsub(%r(/+), '/')
103
+ end
104
+
105
+ def generate(url, content_type, default_path=working_directory)
106
+ prefix = load_paths.detect { |load_path| File.exists?(File.join(load_path, url)) } || default_path
107
+ path = File.join(prefix, url)
108
+ @context.send(:get, absolutize_url(url)) do
109
+ headers 'Content-Type' => content_type
110
+ File.read(path)
111
+ end
112
+ end
113
+
114
+ def parse_args(args)
115
+ options = OpenStruct.new
116
+ options.browser = "Firefox"
117
+ options.rails = false
118
+ options.server = false
119
+ options.paths = []
120
+
121
+ opts = OptionParser.new do |opts|
122
+ opts.banner = "Usage: screwdriver [options] suite"
123
+
124
+ opts.on("-b", "--browser BROWSER", "Specify the browser to use (default: Firefox)") do |browser|
125
+ options.browser = browser
126
+ end
127
+
128
+ opts.on("-p", "--load-paths src,dist,etc", Array, "Adds additional load paths from which files can be served.") do |paths|
129
+ options.paths = paths
130
+ end
131
+
132
+ opts.on("--rails", "Enable Rails integration (serves files from the RAILS_ROOT/public/javascripts directory)") do
133
+ options.rails = true
134
+ end
135
+
136
+ opts.on("-s", "--server", "Keeps the server running after completion") do
137
+ options.server = true
138
+ end
139
+
140
+ opts.on_tail("-h", "--help", "Show this message") do
141
+ puts opts
142
+ exit!
143
+ end
144
+ end
145
+
146
+ opts.parse!(args)
147
+
148
+ if args.empty?
149
+ puts opts
150
+ exit!
151
+ else
152
+ @browser = eval("Screw::Driver::Browser::#{options.browser}.new")
153
+ @rails = options.rails
154
+ @server = options.server
155
+ @path = File.join(Dir.pwd, args.shift)
156
+ setup_load_paths options.paths
157
+ end
158
+ end
159
+
160
+ def setup_load_paths(paths=[])
161
+ @load_paths = paths.map { |path| File.join(Dir.pwd, path) }
162
+ @load_paths << File.join(File.dirname(__FILE__), '..', 'js')
163
+ @load_paths << File.dirname(@path)
164
+ end
165
+
166
+ def doc
167
+ @doc ||= extended_doc(File.open(@path))
168
+ end
169
+
170
+ def extended_doc(file)
171
+ hpricot_doc = Hpricot(file)
172
+ hpricot_doc.search('script').last.after(%(<base href="http://localhost:4567">))
173
+ hpricot_doc.search('script').each do |node|
174
+ case File.basename(node['src'])
175
+ when "screw.behaviors.js" then node.insert_js(:before, 'jquery.ajax_queue.js')
176
+ when "screw.events.js" then node.insert_js(:after, 'screw.driver.js')
177
+ end
178
+ end and hpricot_doc
179
+ end
180
+ end
181
+ end
182
+ end
metadata ADDED
@@ -0,0 +1,83 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: nakajima-screw-driver
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.2
5
+ platform: ruby
6
+ authors:
7
+ - Pat Nakajima
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+
12
+ date: 2008-10-23 00:00:00 -07:00
13
+ default_executable: screwdriver
14
+ dependencies:
15
+ - !ruby/object:Gem::Dependency
16
+ name: sinatra
17
+ version_requirement:
18
+ version_requirements: !ruby/object:Gem::Requirement
19
+ requirements:
20
+ - - ">="
21
+ - !ruby/object:Gem::Version
22
+ version: "0"
23
+ version:
24
+ - !ruby/object:Gem::Dependency
25
+ name: hpricot
26
+ version_requirement:
27
+ version_requirements: !ruby/object:Gem::Requirement
28
+ requirements:
29
+ - - ">="
30
+ - !ruby/object:Gem::Version
31
+ version: "0"
32
+ version:
33
+ description:
34
+ email: patnakajima@gmail.com
35
+ executables:
36
+ - screwdriver
37
+ extensions: []
38
+
39
+ extra_rdoc_files: []
40
+
41
+ files:
42
+ - README.textile
43
+ - Rakefile
44
+ - bin/screwdriver
45
+ - lib/browser.rb
46
+ - lib/browsers/firefox.rb
47
+ - lib/browsers/safari.rb
48
+ - lib/ext/string.rb
49
+ - lib/ext/hpricot.rb
50
+ - lib/helpers.rb
51
+ - lib/rails.rb
52
+ - lib/suite.rb
53
+ - lib/server.rb
54
+ - js/jquery.ajax_queue.js
55
+ - js/screw.driver.js
56
+ has_rdoc: false
57
+ homepage: http://github.com/nakajima/screw-driver
58
+ post_install_message:
59
+ rdoc_options: []
60
+
61
+ require_paths:
62
+ - lib
63
+ required_ruby_version: !ruby/object:Gem::Requirement
64
+ requirements:
65
+ - - ">="
66
+ - !ruby/object:Gem::Version
67
+ version: "0"
68
+ version:
69
+ required_rubygems_version: !ruby/object:Gem::Requirement
70
+ requirements:
71
+ - - ">="
72
+ - !ruby/object:Gem::Version
73
+ version: "0"
74
+ version:
75
+ requirements: []
76
+
77
+ rubyforge_project:
78
+ rubygems_version: 1.2.0
79
+ signing_key:
80
+ specification_version: 2
81
+ summary: Run your Screw.Unit specs from the command line.
82
+ test_files: []
83
+