jspec 2.11.2
Sign up to get free protection for your applications and to get access to all the features.
- data/History.rdoc +522 -0
- data/Manifest +57 -0
- data/README.rdoc +825 -0
- data/Rakefile +75 -0
- data/bin/jspec +305 -0
- data/jspec.gemspec +44 -0
- data/lib/images/bg.png +0 -0
- data/lib/images/hr.png +0 -0
- data/lib/images/loading.gif +0 -0
- data/lib/images/sprites.bg.png +0 -0
- data/lib/images/sprites.png +0 -0
- data/lib/images/vr.png +0 -0
- data/lib/jspec.css +145 -0
- data/lib/jspec.jquery.js +71 -0
- data/lib/jspec.js +1771 -0
- data/lib/jspec.shell.js +36 -0
- data/lib/jspec.timers.js +90 -0
- data/lib/jspec.xhr.js +183 -0
- data/server/browsers.rb +228 -0
- data/server/helpers.rb +82 -0
- data/server/routes.rb +57 -0
- data/server/server.rb +88 -0
- data/spec/async +1 -0
- data/spec/env.js +695 -0
- data/spec/fixtures/test.html +1 -0
- data/spec/fixtures/test.json +1 -0
- data/spec/fixtures/test.xml +5 -0
- data/spec/helpers.js +66 -0
- data/spec/server.rb +2 -0
- data/spec/spec.dom.html +34 -0
- data/spec/spec.fixtures.js +18 -0
- data/spec/spec.grammar-less.js +34 -0
- data/spec/spec.grammar.js +226 -0
- data/spec/spec.jquery.js +176 -0
- data/spec/spec.jquery.xhr.js +65 -0
- data/spec/spec.js +166 -0
- data/spec/spec.matchers.js +493 -0
- data/spec/spec.modules.js +67 -0
- data/spec/spec.node.js +46 -0
- data/spec/spec.rhino.js +17 -0
- data/spec/spec.server.html +29 -0
- data/spec/spec.shared-behaviors.js +80 -0
- data/spec/spec.utils.js +279 -0
- data/spec/spec.xhr.js +156 -0
- data/templates/default/History.rdoc +4 -0
- data/templates/default/README.rdoc +29 -0
- data/templates/default/lib/yourlib.core.js +2 -0
- data/templates/default/spec/server.rb +4 -0
- data/templates/default/spec/spec.core.js +8 -0
- data/templates/default/spec/spec.dom.html +20 -0
- data/templates/default/spec/spec.rhino.js +8 -0
- data/templates/default/spec/spec.server.html +16 -0
- data/templates/rails/server.rb +4 -0
- data/templates/rails/spec.application.js +8 -0
- data/templates/rails/spec.dom.html +20 -0
- data/templates/rails/spec.rhino.js +8 -0
- data/templates/rails/spec.server.html +16 -0
- metadata +168 -0
data/lib/jspec.shell.js
ADDED
@@ -0,0 +1,36 @@
|
|
1
|
+
|
2
|
+
// JSpec - Shell - Copyright TJ Holowaychuk <tj@vision-media.ca> (MIT Licensed)
|
3
|
+
|
4
|
+
;(function(){
|
5
|
+
|
6
|
+
var _quit = quit
|
7
|
+
|
8
|
+
Shell = {
|
9
|
+
|
10
|
+
// --- Global
|
11
|
+
|
12
|
+
main: this,
|
13
|
+
|
14
|
+
// --- Commands
|
15
|
+
|
16
|
+
commands: {
|
17
|
+
quit: ['Terminate the shell', function(){ _quit() }],
|
18
|
+
exit: ['Terminate the shell', function(){ _quit() }]
|
19
|
+
},
|
20
|
+
|
21
|
+
/**
|
22
|
+
* Start the interactive shell.
|
23
|
+
*
|
24
|
+
* @api public
|
25
|
+
*/
|
26
|
+
|
27
|
+
start : function() {
|
28
|
+
for (var name in this.commands)
|
29
|
+
if (this.commands.hasOwnProperty(name))
|
30
|
+
this.main.__defineGetter__(name, this.commands[name][1])
|
31
|
+
}
|
32
|
+
}
|
33
|
+
|
34
|
+
Shell.start()
|
35
|
+
|
36
|
+
})()
|
data/lib/jspec.timers.js
ADDED
@@ -0,0 +1,90 @@
|
|
1
|
+
|
2
|
+
// JSpec - Mock Timers - Copyright TJ Holowaychuk <tj@vision-media.ca> (MIT Licensed)
|
3
|
+
|
4
|
+
;(function(){
|
5
|
+
|
6
|
+
/**
|
7
|
+
* Version.
|
8
|
+
*/
|
9
|
+
|
10
|
+
mockTimersVersion = '1.0.1'
|
11
|
+
|
12
|
+
/**
|
13
|
+
* Localized timer stack.
|
14
|
+
*/
|
15
|
+
|
16
|
+
var timers = []
|
17
|
+
|
18
|
+
/**
|
19
|
+
* Set mock timeout with _callback_ and timeout of _ms_.
|
20
|
+
*
|
21
|
+
* @param {function} callback
|
22
|
+
* @param {int} ms
|
23
|
+
* @return {int}
|
24
|
+
* @api public
|
25
|
+
*/
|
26
|
+
|
27
|
+
setTimeout = function(callback, ms) {
|
28
|
+
var id
|
29
|
+
return id = setInterval(function(){
|
30
|
+
callback()
|
31
|
+
clearInterval(id)
|
32
|
+
}, ms)
|
33
|
+
}
|
34
|
+
|
35
|
+
/**
|
36
|
+
* Set mock interval with _callback_ and interval of _ms_.
|
37
|
+
*
|
38
|
+
* @param {function} callback
|
39
|
+
* @param {int} ms
|
40
|
+
* @return {int}
|
41
|
+
* @api public
|
42
|
+
*/
|
43
|
+
|
44
|
+
setInterval = function(callback, ms) {
|
45
|
+
callback.step = ms, callback.current = callback.last = 0
|
46
|
+
return timers[timers.length] = callback, timers.length
|
47
|
+
}
|
48
|
+
|
49
|
+
/**
|
50
|
+
* Destroy timer with _id_.
|
51
|
+
*
|
52
|
+
* @param {int} id
|
53
|
+
* @return {bool}
|
54
|
+
* @api public
|
55
|
+
*/
|
56
|
+
|
57
|
+
clearInterval = function(id) {
|
58
|
+
return delete timers[--id]
|
59
|
+
}
|
60
|
+
|
61
|
+
/**
|
62
|
+
* Reset timers.
|
63
|
+
*
|
64
|
+
* @return {array}
|
65
|
+
* @api public
|
66
|
+
*/
|
67
|
+
|
68
|
+
resetTimers = function() {
|
69
|
+
return timers = []
|
70
|
+
}
|
71
|
+
|
72
|
+
/**
|
73
|
+
* Increment each timers internal clock by _ms_.
|
74
|
+
*
|
75
|
+
* @param {int} ms
|
76
|
+
* @api public
|
77
|
+
*/
|
78
|
+
|
79
|
+
tick = function(ms) {
|
80
|
+
for (var i = 0, len = timers.length; i < len; ++i)
|
81
|
+
if (timers[i] && (timers[i].current += ms))
|
82
|
+
if (timers[i].current - timers[i].last >= timers[i].step) {
|
83
|
+
var times = Math.floor((timers[i].current - timers[i].last) / timers[i].step)
|
84
|
+
var remainder = (timers[i].current - timers[i].last) % timers[i].step
|
85
|
+
timers[i].last = timers[i].current - remainder
|
86
|
+
while (times-- && timers[i]) timers[i]()
|
87
|
+
}
|
88
|
+
}
|
89
|
+
|
90
|
+
})()
|
data/lib/jspec.xhr.js
ADDED
@@ -0,0 +1,183 @@
|
|
1
|
+
|
2
|
+
// JSpec - XHR - Copyright TJ Holowaychuk <tj@vision-media.ca> (MIT Licensed)
|
3
|
+
|
4
|
+
(function(){
|
5
|
+
|
6
|
+
// --- Original XMLHttpRequest
|
7
|
+
|
8
|
+
var OriginalXMLHttpRequest = 'XMLHttpRequest' in this ?
|
9
|
+
XMLHttpRequest :
|
10
|
+
function(){}
|
11
|
+
|
12
|
+
// --- MockXMLHttpRequest
|
13
|
+
|
14
|
+
var MockXMLHttpRequest = function() {
|
15
|
+
this.requestHeaders = {}
|
16
|
+
}
|
17
|
+
|
18
|
+
MockXMLHttpRequest.prototype = {
|
19
|
+
status: 0,
|
20
|
+
async: true,
|
21
|
+
readyState: 0,
|
22
|
+
responseText: '',
|
23
|
+
abort: function(){},
|
24
|
+
onreadystatechange: function(){},
|
25
|
+
|
26
|
+
/**
|
27
|
+
* Return response headers hash.
|
28
|
+
*/
|
29
|
+
|
30
|
+
getAllResponseHeaders : function(){
|
31
|
+
return this.responseHeaders
|
32
|
+
},
|
33
|
+
|
34
|
+
/**
|
35
|
+
* Return case-insensitive value for header _name_.
|
36
|
+
*/
|
37
|
+
|
38
|
+
getResponseHeader : function(name) {
|
39
|
+
return this.responseHeaders[name.toLowerCase()]
|
40
|
+
},
|
41
|
+
|
42
|
+
/**
|
43
|
+
* Set case-insensitive _value_ for header _name_.
|
44
|
+
*/
|
45
|
+
|
46
|
+
setRequestHeader : function(name, value) {
|
47
|
+
this.requestHeaders[name.toLowerCase()] = value
|
48
|
+
},
|
49
|
+
|
50
|
+
/**
|
51
|
+
* Open mock request.
|
52
|
+
*/
|
53
|
+
|
54
|
+
open : function(method, url, async, user, password) {
|
55
|
+
this.user = user
|
56
|
+
this.password = password
|
57
|
+
this.url = url
|
58
|
+
this.readyState = 1
|
59
|
+
this.method = method.toUpperCase()
|
60
|
+
if (async != undefined) this.async = async
|
61
|
+
if (this.async) this.onreadystatechange()
|
62
|
+
},
|
63
|
+
|
64
|
+
/**
|
65
|
+
* Send request _data_.
|
66
|
+
*/
|
67
|
+
|
68
|
+
send : function(data) {
|
69
|
+
this.data = data
|
70
|
+
this.readyState = 4
|
71
|
+
if (this.method == 'HEAD') this.responseText = null
|
72
|
+
this.responseHeaders['content-length'] = (this.responseText || '').length
|
73
|
+
if(this.async) this.onreadystatechange()
|
74
|
+
}
|
75
|
+
}
|
76
|
+
|
77
|
+
// --- Response status codes
|
78
|
+
|
79
|
+
JSpec.statusCodes = {
|
80
|
+
100: 'Continue',
|
81
|
+
101: 'Switching Protocols',
|
82
|
+
200: 'OK',
|
83
|
+
201: 'Created',
|
84
|
+
202: 'Accepted',
|
85
|
+
203: 'Non-Authoritative Information',
|
86
|
+
204: 'No Content',
|
87
|
+
205: 'Reset Content',
|
88
|
+
206: 'Partial Content',
|
89
|
+
300: 'Multiple Choice',
|
90
|
+
301: 'Moved Permanently',
|
91
|
+
302: 'Found',
|
92
|
+
303: 'See Other',
|
93
|
+
304: 'Not Modified',
|
94
|
+
305: 'Use Proxy',
|
95
|
+
307: 'Temporary Redirect',
|
96
|
+
400: 'Bad Request',
|
97
|
+
401: 'Unauthorized',
|
98
|
+
402: 'Payment Required',
|
99
|
+
403: 'Forbidden',
|
100
|
+
404: 'Not Found',
|
101
|
+
405: 'Method Not Allowed',
|
102
|
+
406: 'Not Acceptable',
|
103
|
+
407: 'Proxy Authentication Required',
|
104
|
+
408: 'Request Timeout',
|
105
|
+
409: 'Conflict',
|
106
|
+
410: 'Gone',
|
107
|
+
411: 'Length Required',
|
108
|
+
412: 'Precondition Failed',
|
109
|
+
413: 'Request Entity Too Large',
|
110
|
+
414: 'Request-URI Too Long',
|
111
|
+
415: 'Unsupported Media Type',
|
112
|
+
416: 'Requested Range Not Satisfiable',
|
113
|
+
417: 'Expectation Failed',
|
114
|
+
422: 'Unprocessable Entity',
|
115
|
+
500: 'Internal Server Error',
|
116
|
+
501: 'Not Implemented',
|
117
|
+
502: 'Bad Gateway',
|
118
|
+
503: 'Service Unavailable',
|
119
|
+
504: 'Gateway Timeout',
|
120
|
+
505: 'HTTP Version Not Supported'
|
121
|
+
}
|
122
|
+
|
123
|
+
/**
|
124
|
+
* Mock XMLHttpRequest requests.
|
125
|
+
*
|
126
|
+
* mockRequest().and_return('some data', 'text/plain', 200, { 'X-SomeHeader' : 'somevalue' })
|
127
|
+
*
|
128
|
+
* @return {hash}
|
129
|
+
* @api public
|
130
|
+
*/
|
131
|
+
|
132
|
+
function mockRequest() {
|
133
|
+
return { and_return : function(body, type, status, headers) {
|
134
|
+
XMLHttpRequest = MockXMLHttpRequest
|
135
|
+
status = status || 200
|
136
|
+
headers = headers || {}
|
137
|
+
headers['content-type'] = type
|
138
|
+
JSpec.extend(XMLHttpRequest.prototype, {
|
139
|
+
responseText: body,
|
140
|
+
responseHeaders: headers,
|
141
|
+
status: status,
|
142
|
+
statusText: JSpec.statusCodes[status]
|
143
|
+
})
|
144
|
+
}}
|
145
|
+
}
|
146
|
+
|
147
|
+
/**
|
148
|
+
* Unmock XMLHttpRequest requests.
|
149
|
+
*
|
150
|
+
* @api public
|
151
|
+
*/
|
152
|
+
|
153
|
+
function unmockRequest() {
|
154
|
+
XMLHttpRequest = OriginalXMLHttpRequest
|
155
|
+
}
|
156
|
+
|
157
|
+
JSpec.include({
|
158
|
+
name: 'Mock XHR',
|
159
|
+
|
160
|
+
// --- Utilities
|
161
|
+
|
162
|
+
utilities : {
|
163
|
+
mockRequest: mockRequest,
|
164
|
+
unmockRequest: unmockRequest
|
165
|
+
},
|
166
|
+
|
167
|
+
// --- Hooks
|
168
|
+
|
169
|
+
afterSpec : function() {
|
170
|
+
this.utilities.unmockRequest()
|
171
|
+
},
|
172
|
+
|
173
|
+
// --- DSLs
|
174
|
+
|
175
|
+
DSLs : {
|
176
|
+
snake : {
|
177
|
+
mock_request: mockRequest,
|
178
|
+
unmock_request: unmockRequest
|
179
|
+
}
|
180
|
+
}
|
181
|
+
|
182
|
+
})
|
183
|
+
})()
|
data/server/browsers.rb
ADDED
@@ -0,0 +1,228 @@
|
|
1
|
+
|
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
|
180
|
+
end
|
181
|
+
|
182
|
+
def supported?
|
183
|
+
windows?
|
184
|
+
end
|
185
|
+
|
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
|
226
|
+
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
|