visionmedia-jspec 2.8.4 → 2.9.0

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