jspec 2.11.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (58) hide show
  1. data/History.rdoc +522 -0
  2. data/Manifest +57 -0
  3. data/README.rdoc +825 -0
  4. data/Rakefile +75 -0
  5. data/bin/jspec +305 -0
  6. data/jspec.gemspec +44 -0
  7. data/lib/images/bg.png +0 -0
  8. data/lib/images/hr.png +0 -0
  9. data/lib/images/loading.gif +0 -0
  10. data/lib/images/sprites.bg.png +0 -0
  11. data/lib/images/sprites.png +0 -0
  12. data/lib/images/vr.png +0 -0
  13. data/lib/jspec.css +145 -0
  14. data/lib/jspec.jquery.js +71 -0
  15. data/lib/jspec.js +1771 -0
  16. data/lib/jspec.shell.js +36 -0
  17. data/lib/jspec.timers.js +90 -0
  18. data/lib/jspec.xhr.js +183 -0
  19. data/server/browsers.rb +228 -0
  20. data/server/helpers.rb +82 -0
  21. data/server/routes.rb +57 -0
  22. data/server/server.rb +88 -0
  23. data/spec/async +1 -0
  24. data/spec/env.js +695 -0
  25. data/spec/fixtures/test.html +1 -0
  26. data/spec/fixtures/test.json +1 -0
  27. data/spec/fixtures/test.xml +5 -0
  28. data/spec/helpers.js +66 -0
  29. data/spec/server.rb +2 -0
  30. data/spec/spec.dom.html +34 -0
  31. data/spec/spec.fixtures.js +18 -0
  32. data/spec/spec.grammar-less.js +34 -0
  33. data/spec/spec.grammar.js +226 -0
  34. data/spec/spec.jquery.js +176 -0
  35. data/spec/spec.jquery.xhr.js +65 -0
  36. data/spec/spec.js +166 -0
  37. data/spec/spec.matchers.js +493 -0
  38. data/spec/spec.modules.js +67 -0
  39. data/spec/spec.node.js +46 -0
  40. data/spec/spec.rhino.js +17 -0
  41. data/spec/spec.server.html +29 -0
  42. data/spec/spec.shared-behaviors.js +80 -0
  43. data/spec/spec.utils.js +279 -0
  44. data/spec/spec.xhr.js +156 -0
  45. data/templates/default/History.rdoc +4 -0
  46. data/templates/default/README.rdoc +29 -0
  47. data/templates/default/lib/yourlib.core.js +2 -0
  48. data/templates/default/spec/server.rb +4 -0
  49. data/templates/default/spec/spec.core.js +8 -0
  50. data/templates/default/spec/spec.dom.html +20 -0
  51. data/templates/default/spec/spec.rhino.js +8 -0
  52. data/templates/default/spec/spec.server.html +16 -0
  53. data/templates/rails/server.rb +4 -0
  54. data/templates/rails/spec.application.js +8 -0
  55. data/templates/rails/spec.dom.html +20 -0
  56. data/templates/rails/spec.rhino.js +8 -0
  57. data/templates/rails/spec.server.html +16 -0
  58. metadata +168 -0
@@ -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
+ })()
@@ -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
+ })()
@@ -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