visionmedia-jspec 2.8.4 → 2.9.0

Sign up to get free protection for your applications and to get access to all the features.
data/server/browsers.rb CHANGED
@@ -1,16 +1,228 @@
1
1
 
2
- module JSpec
3
- class Browser
4
- def open url
5
- `open -g -a #{name} #{url}`
2
+ require 'rbconfig'
3
+
4
+ #--
5
+ # Browser
6
+ #++
7
+
8
+ class Browser
9
+
10
+ ##
11
+ # Check if the user agent _string_ matches this browser.
12
+
13
+ def self.matches_agent? string; end
14
+
15
+ ##
16
+ # Check if the browser matches the name _string_.
17
+
18
+ def self.matches_name? string; end
19
+
20
+ ##
21
+ # Subclasses.
22
+
23
+ def self.subclasses
24
+ @subclasses ||= []
25
+ end
26
+
27
+ ##
28
+ # Stack subclasses.
29
+
30
+ def self.inherited subclass
31
+ subclasses << subclass
32
+ end
33
+
34
+ ##
35
+ # Weither or not the browser is supported.
36
+
37
+ def supported?; true end
38
+
39
+ ##
40
+ # Server setup.
41
+
42
+ def setup; end
43
+
44
+ ##
45
+ # Server teardown.
46
+
47
+ def teardown; end
48
+
49
+ ##
50
+ # Host environment.
51
+
52
+ def host
53
+ Config::CONFIG['host']
54
+ end
55
+
56
+ ##
57
+ # Check if we are using macos.
58
+
59
+ def macos?
60
+ host.include? 'darwin'
61
+ end
62
+
63
+ ##
64
+ # Check if we are using windows.
65
+
66
+ def windows?
67
+ host.include? 'mswin'
68
+ end
69
+
70
+ ##
71
+ # Check if we are using linux.
72
+
73
+ def linux?
74
+ host.include? 'linux'
75
+ end
76
+
77
+ ##
78
+ # Run applescript _code_.
79
+
80
+ def applescript code
81
+ raise "Can't run AppleScript on #{host}" unless macos?
82
+ system "osascript -e '#{code}' 2>&1 >/dev/null"
83
+ end
84
+
85
+ #--
86
+ # Firefox
87
+ #++
88
+
89
+ class Firefox < self
90
+ def self.matches_agent? string
91
+ string =~ /firefox/i
92
+ end
93
+
94
+ def self.matches_name? string
95
+ string =~ /ff|firefox|mozilla/i
96
+ end
97
+
98
+ def visit uri
99
+ system "open -g -a Firefox '#{uri}'" if macos?
100
+ system "firefox #{uri}" if linux?
101
+ system "#{File.join(ENV['ProgramFiles'] || 'c:\Program Files', '\Mozilla Firefox\firefox.exe')} #{uri}" if windows?
102
+ end
103
+
104
+ def to_s
105
+ 'Firefox'
106
+ end
107
+ end
108
+
109
+ #--
110
+ # Safari
111
+ #++
112
+
113
+ class Safari < self
114
+ def self.matches_agent? string
115
+ string =~ /safari/i && string !~ /chrome/i
116
+ end
117
+
118
+ def self.matches_name? string
119
+ string =~ /safari/i
120
+ end
121
+
122
+ def supported?
123
+ macos?
124
+ end
125
+
126
+ def setup
127
+ applescript 'tell application "Safari" to make new document'
128
+ end
129
+
130
+ def visit uri
131
+ applescript 'tell application "Safari" to set URL of front document to "' + uri + '"'
132
+ end
133
+
134
+ def matches_agent? string
135
+ string =~ /safari/i
136
+ end
137
+
138
+ def to_s
139
+ 'Safari'
140
+ end
141
+ end
142
+
143
+ #--
144
+ # Chrome
145
+ #++
146
+
147
+ class Chrome < self
148
+ def self.matches_agent? string
149
+ string =~ /chrome/i
150
+ end
151
+
152
+ def self.matches_name? string
153
+ string =~ /google|chrome/i
154
+ end
155
+
156
+ def supported?
157
+ macos?
158
+ end
159
+
160
+ def visit uri
161
+ system "open -g -a Chromium #{uri}" if macos?
162
+ end
163
+
164
+ def to_s
165
+ 'Chrome'
166
+ end
167
+ end
168
+
169
+ #--
170
+ # Internet Explorer
171
+ #++
172
+
173
+ class IE < self
174
+ def self.matches_agent? string
175
+ string =~ /microsoft/i
176
+ end
177
+
178
+ def self.matches_name? string
179
+ string =~ /ie|explorer/i
6
180
  end
7
181
 
8
- def name
9
- self.class.to_s.split('::').last
182
+ def supported?
183
+ windows?
10
184
  end
11
185
 
12
- class Firefox < self; end
13
- class Safari < self; end
14
- class Opera < self; end
186
+ def setup
187
+ require 'win32ole'
188
+ end
189
+
190
+ def visit uri
191
+ ie = WIN32OLE.new 'InternetExplorer.Application'
192
+ ie.visible = true
193
+ ie.Navigate uri
194
+ while ie.ReadyState != 4 do
195
+ sleep 1
196
+ end
197
+ end
198
+
199
+ def to_s
200
+ 'Internet Explorer'
201
+ end
202
+ end
203
+
204
+ #--
205
+ # Opera
206
+ #++
207
+
208
+ class Opera < self
209
+ def self.matches_agent? string
210
+ string =~ /opera/i
211
+ end
212
+
213
+ def self.matches_name? string
214
+ string =~ /opera/i
215
+ end
216
+
217
+ def visit uri
218
+ system "open -g -a Opera #{uri}" if macos?
219
+ system "c:\Program Files\Opera\Opera.exe #{uri}" if windows?
220
+ system "opera #{uri}" if linux?
221
+ end
222
+
223
+ def to_s
224
+ 'Opera'
225
+ end
15
226
  end
16
- end
227
+
228
+ end
data/server/helpers.rb ADDED
@@ -0,0 +1,82 @@
1
+
2
+ helpers do
3
+
4
+ ##
5
+ # Return dotted assertion graph for _assertions_.
6
+
7
+ def assertion_graph_for assertions
8
+ return if assertions.empty?
9
+ assertions.map do |assertion|
10
+ assertion['passed'] ? green('.') : red('.')
11
+ end.join
12
+ end
13
+
14
+ ##
15
+ # Override Sinatra's #send_file to prevent caching.
16
+
17
+ def send_file path, opts = {}
18
+ stat = File.stat(path)
19
+ response['Cache-Control'] = 'no-cache'
20
+ content_type media_type(opts[:type]) ||
21
+ media_type(File.extname(path)) ||
22
+ response['Content-Type'] ||
23
+ 'application/octet-stream'
24
+ response['Content-Length'] ||= (opts[:length] || stat.size).to_s
25
+
26
+ if opts[:disposition] == 'attachment' || opts[:filename]
27
+ attachment opts[:filename] || path
28
+ elsif opts[:disposition] == 'inline'
29
+ response['Content-Disposition'] = 'inline'
30
+ end
31
+
32
+ halt ::Sinatra::Application::StaticFile.open(path, 'rb')
33
+ rescue Errno::ENOENT
34
+ not_found
35
+ end
36
+
37
+ ##
38
+ # Find the browser name for the current user agent.
39
+
40
+ def browser_name
41
+ Browser.subclasses.find do |browser|
42
+ browser.matches_agent? env['HTTP_USER_AGENT']
43
+ end.new
44
+ rescue
45
+ 'Unknown'
46
+ end
47
+
48
+ ##
49
+ # Wrap _string_ with ansi escape sequence using _code_.
50
+
51
+ def color string, code
52
+ "\e[#{code}m#{string}\e[0m"
53
+ end
54
+
55
+ ##
56
+ # Bold _string_.
57
+
58
+ def bold string
59
+ color string, 1
60
+ end
61
+
62
+ ##
63
+ # Color _string_ red.
64
+
65
+ def red string
66
+ color string, 31
67
+ end
68
+
69
+ ##
70
+ # Color _string_ green.
71
+
72
+ def green string
73
+ color string, 32
74
+ end
75
+
76
+ ##
77
+ # Color _string_ blue.
78
+
79
+ def blue string
80
+ color string, 34
81
+ end
82
+ end
data/server/routes.rb ADDED
@@ -0,0 +1,57 @@
1
+
2
+ get '/jspec/*' do |path|
3
+ send_file JSPEC_ROOT + '/lib/' + path
4
+ end
5
+
6
+ post '/results' do
7
+ require 'json'
8
+ data = JSON.parse request.body.read
9
+ if data['options'].include?('verbose') && data['options']['verbose'] ||
10
+ data['options'].include?('failuresOnly') && data['options']['failuresOnly']
11
+ puts "\n\n %s Passes: %s Failures: %s\n\n" % [
12
+ bold(browser_name),
13
+ green(data['stats']['passes']),
14
+ red(data['stats']['failures'])]
15
+ data['results'].compact.each do |suite|
16
+ specs = suite['specs'].compact.map do |spec|
17
+ case spec['status'].to_sym
18
+ when :pass
19
+ next if data['options'].include?('failuresOnly') && data['options']['failuresOnly']
20
+ ' ' + green(spec['description']) + assertion_graph_for(spec['assertions']).to_s + "\n"
21
+ when :fail
22
+ " #{red(spec['description'])}\n #{spec['message']}\n\n"
23
+ else
24
+ " #{blue(spec['description'])}\n"
25
+ end
26
+ end.join
27
+ unless specs.strip.empty?
28
+ puts "\n " + bold(suite['description'])
29
+ puts specs
30
+ end
31
+ end
32
+ else
33
+ puts "%20s Passes: %s Failures: %s" % [
34
+ bold(browser_name),
35
+ green(data['stats']['passes']),
36
+ red(data['stats']['failures'])]
37
+ end
38
+ halt 200
39
+ end
40
+
41
+ get '/*' do |path|
42
+ pass unless File.exists?(path)
43
+ send_file path
44
+ end
45
+
46
+ #--
47
+ # Simulation Routes
48
+ #++
49
+
50
+ get '/slow/*' do |seconds|
51
+ sleep seconds.to_i
52
+ halt 200
53
+ end
54
+
55
+ get '/status/*' do |code|
56
+ halt code.to_i
57
+ end
data/server/server.rb CHANGED
@@ -1,100 +1,88 @@
1
1
 
2
- require 'rubygems'
3
- require 'rack'
4
- require 'server/browsers'
2
+ $:.unshift File.dirname(__FILE__)
3
+
4
+ require 'sinatra'
5
+ require 'thread'
6
+ require 'browsers'
7
+ require 'helpers'
8
+ require 'routes'
5
9
 
6
10
  module JSpec
7
11
  class Server
8
- attr_reader :responses, :browsers, :root
9
12
 
10
- def initialize options = {}
11
- @responses = []
12
- @browsers = options.delete :browsers
13
- @root = options.delete :root
14
- end
13
+ ##
14
+ # Suite HTML.
15
15
 
16
- def call env
17
- request = Rack::Request.new env
18
- path = request.path_info
19
- body = case path
20
- when '/'
21
- agent = env['HTTP_USER_AGENT']
22
- responses << browser(agent)
23
- display_results browser(agent), request['failures'], request['passes']
24
- type = 'text/plain'
25
- 'close'
26
- when /jspec/
27
- type = 'application/javascript'
28
- File.read File.join(JSPEC_ROOT, 'lib', File.basename(path))
29
- else
30
- type = Rack::Mime.mime_type File.extname(path)
31
- File.read File.join(root, path) rescue ''
32
- end
33
- [200, { 'Content-Type' => type, 'Content-Length' => body.length.to_s }, body]
34
- end
35
-
36
- def display_results browser, failures, passes
37
- puts '%-14s - passes: %s failures: %s' % [bold(browser), green(passes), red(failures)]
38
- end
39
-
40
- def browser string
41
- case string
42
- when /Safari/ ; :Safari
43
- when /Firefox/ ; :Firefox
44
- when /MSIE/ ; :MSIE
45
- when /Opera/ ; :Opera
46
- end
47
- end
48
-
49
- def bold string
50
- color string, 1
51
- end
52
-
53
- def red string
54
- color string, 31
55
- end
56
-
57
- def green string
58
- color string, 32
59
- end
60
-
61
- def color string, code
62
- "\e[#{code}m#{string}\e[m"
16
+ attr_accessor :suite
17
+
18
+ ##
19
+ # Host string.
20
+
21
+ attr_reader :host
22
+
23
+ ##
24
+ # Port number.
25
+
26
+ attr_reader :port
27
+
28
+ ##
29
+ # Server instance.
30
+
31
+ attr_reader :server
32
+
33
+ ##
34
+ # Initialize.
35
+
36
+ def initialize suite, port
37
+ @suite, @port, @host = suite, port, :localhost
63
38
  end
64
39
 
65
- def when_finished &block
66
- Thread.new {
67
- sleep 0.1 while responses.length < browsers.length
68
- yield
69
- }
40
+ ##
41
+ # URI formed by the given host and port.
42
+
43
+ def uri
44
+ 'http://%s:%d' % [host, port]
70
45
  end
71
46
 
72
- def self.start options, spec
73
- app = Rack::Builder.new do
74
- server = JSpec::Server.new :browsers => options.browsers, :root => '.'
75
- server.when_finished { exit }
76
- run server
77
- end
78
- unless options.server_only
79
- Thread.new {
80
- sleep 2
81
- puts "Running browsers: #{options.browsers.join(', ')}\n\n"
82
- run_browsers options.browsers, spec
47
+ ##
48
+ # Start the server with _browsers_ which defaults to all supported browsers.
49
+
50
+ def start browsers = nil
51
+ browsers ||= Browser.subclasses.map { |browser| browser.new }
52
+ browsers.map do |browser|
53
+ Thread.new {
54
+ sleep 1
55
+ if browser.supported?
56
+ browser.setup
57
+ browser.visit uri + '/' + suite
58
+ browser.teardown
59
+ end
83
60
  }
84
- end
85
- puts "JSpec server started\n"
86
- Rack::Handler::Mongrel.run app, :Port => 4444
87
- self
61
+ end.push(Thread.new {
62
+ start!
63
+ }).reverse.each { |thread| thread.join }
88
64
  end
89
65
 
90
- def self.run_browsers browsers, spec
91
- browsers.each do |name|
92
- browser(name).open "http://localhost:4444/#{spec}"
66
+ private
67
+
68
+ #:nodoc:
69
+
70
+ def start!
71
+ Sinatra::Application.class_eval do
72
+ begin
73
+ $stderr.puts 'Started JSpec server at http://%s:%d' % [host, port.to_i]
74
+ detect_rack_handler.run self, :Host => host, :Port => port do |server|
75
+ trap 'INT' do
76
+ server.respond_to?(:stop!) ? server.stop! : server.stop
77
+ end
78
+ end
79
+ rescue Errno::EADDRINUSE
80
+ raise "Port #{port} already in use"
81
+ rescue Errno::EACCES
82
+ raise "Permission Denied on port #{port}"
83
+ end
93
84
  end
94
85
  end
95
86
 
96
- def self.browser name
97
- eval("JSpec::Browser::#{name}").new
98
- end
99
87
  end
100
88
  end
data/spec/server.rb ADDED
@@ -0,0 +1,2 @@
1
+
2
+ puts 'Use spec/jspec.rb to alter anything you like, provide routes, browsers, etc'
data/spec/spec.jquery.js CHANGED
@@ -20,16 +20,16 @@ describe 'jQuery'
20
20
 
21
21
  describe 'async'
22
22
  it 'should load mah cookies (textfile)'
23
- $.post('async', function(text){
23
+ $.get('async', function(text){
24
24
  text.should_eql 'cookies!'
25
25
  })
26
26
  end
27
27
 
28
28
  it 'should load mah cookies twice (ensure multiple async requests work)'
29
- $.post('async', function(text){
29
+ $.get('async', function(text){
30
30
  text.should.eql 'cookies!'
31
31
  })
32
- $.post('async', function(text){
32
+ $.get('async', function(text){
33
33
  text.should.not.eql 'rawr'
34
34
  })
35
35
  end
@@ -299,6 +299,7 @@ describe 'Matchers'
299
299
  addPets : function(a, b) { return ['izzy', a, b] }
300
300
  }
301
301
  end
302
+
302
303
  it 'should pass when the method is invoked'
303
304
  personWithPets.should.receive('getPets')
304
305
  personWithPets.getPets()
@@ -1,9 +1,9 @@
1
1
  <html>
2
2
  <head>
3
3
  <script src="http://ajax.googleapis.com/ajax/libs/jquery/1.3.1/jquery.min.js"></script>
4
- <script src="jspec.js"></script>
5
- <script src="jspec.jquery.js"></script>
6
- <script src="jspec.xhr.js"></script>
4
+ <script src="/jspec/jspec.js"></script>
5
+ <script src="/jspec/jspec.jquery.js"></script>
6
+ <script src="/jspec/jspec.xhr.js"></script>
7
7
  <script src="modules.js"></script>
8
8
  <script src="spec.grammar-less.js"></script>
9
9
  <script>
@@ -19,8 +19,8 @@
19
19
  .exec('spec.modules.js')
20
20
  .exec('spec.xhr.js')
21
21
  .exec('spec.jquery.xhr.js')
22
- .run()
23
- .reportToServer()
22
+ .run({ formatter : JSpec.formatters.Server })
23
+ .report()
24
24
  }
25
25
  </script>
26
26
  </head>
data/spec/spec.xhr.js CHANGED
@@ -1,6 +1,6 @@
1
1
 
2
2
  describe 'JSpec'
3
- describe '.mockRequest'
3
+ describe 'Mock XHR'
4
4
  before
5
5
  responseFrom = function(path) {
6
6
  request = new XMLHttpRequest
@@ -10,6 +10,11 @@ describe 'JSpec'
10
10
  }
11
11
  end
12
12
 
13
+ it 'should provide snake DSL methods'
14
+ mock_request.should.equal mockRequest
15
+ unmock_request.should.equal unmockRequest
16
+ end
17
+
13
18
  it 'should mock XMLHttpRequests if unmockRequest() is called or the spec block has finished'
14
19
  original = XMLHttpRequest
15
20
  mockRequest().and_return('test')
@@ -0,0 +1,4 @@
1
+
2
+ get '/lib/*' do |path|
3
+ send_file File.dirname(__FILE__) + '/../lib/' + path
4
+ end
@@ -1,13 +1,13 @@
1
1
  <html>
2
2
  <head>
3
- <script src="jspec.js"></script>
4
- <script src="../lib/yourlib.core.js"></script>
3
+ <script src="/jspec/jspec.js"></script>
4
+ <script src="/lib/yourlib.core.js"></script>
5
5
  <script>
6
6
  function runSuites() {
7
7
  JSpec
8
8
  .exec('spec.core.js')
9
- .run()
10
- .reportToServer()
9
+ .run({ formatter : JSpec.formatters.Server, verbose: true, failuresOnly: true })
10
+ .report()
11
11
  }
12
12
  </script>
13
13
  </head>
@@ -0,0 +1,4 @@
1
+
2
+ get '/public/*' do |path|
3
+ send_file File.dirname(__FILE__) + '/../public/' + path
4
+ end
@@ -1,13 +1,13 @@
1
1
  <html>
2
2
  <head>
3
- <script src="jspec.js"></script>
4
- <script src="../public/javascripts/application.js"></script>
3
+ <script src="/jspec/jspec.js"></script>
4
+ <script src="/public/javascripts/application.js"></script>
5
5
  <script>
6
6
  function runSuites() {
7
7
  JSpec
8
8
  .exec('spec.application.js')
9
- .run()
10
- .reportToServer()
9
+ .run({ formatter : JSpec.formatters.Server, verbose: true, failuresOnly: true })
10
+ .report()
11
11
  }
12
12
  </script>
13
13
  </head>