jspec 2.11.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.
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