nakajima-screw-driver 0.0.2

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/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
+