shenandoah 0.1.3 → 0.2.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.
Files changed (33) hide show
  1. data/.gitignore +1 -0
  2. data/ChangeLog.markdown +9 -0
  3. data/Rakefile +21 -2
  4. data/VERSION.yml +3 -2
  5. data/features/buildr.feature +29 -0
  6. data/features/example_projects/base/Rakefile +7 -0
  7. data/features/example_projects/base/lib/cells.js +105 -0
  8. data/features/example_projects/base/lib/life.js +30 -0
  9. data/features/example_projects/base/spec/cells.html +13 -0
  10. data/features/example_projects/base/spec/cells_spec.js +234 -0
  11. data/features/example_projects/base/spec/life.html +13 -0
  12. data/features/example_projects/base/spec/life_spec.js +28 -0
  13. data/features/plain-rake.feature +30 -0
  14. data/features/rails.feature +39 -0
  15. data/features/step_definitions/buildr_steps.rb +26 -0
  16. data/features/step_definitions/rails_steps.rb +38 -0
  17. data/features/step_definitions/rake_steps.rb +45 -0
  18. data/features/support/env.rb +48 -0
  19. data/lib/shenandoah/css/shenandoah.sass +138 -0
  20. data/lib/shenandoah/javascript/browser/index.js +18 -0
  21. data/lib/shenandoah/javascript/browser/multirunner-single.js +32 -0
  22. data/lib/shenandoah/javascript/browser/multirunner.js +87 -0
  23. data/lib/shenandoah/javascript/common/jquery.parsequery.js +19 -0
  24. data/lib/shenandoah/server.rb +81 -16
  25. data/lib/shenandoah/server/views/index.haml +18 -8
  26. data/lib/shenandoah/server/views/multirunner.haml +6 -0
  27. data/rails_generators/shen_spec/templates/fixture.html.erb +1 -1
  28. data/rails_generators/shenandoah/templates/application.html +1 -1
  29. data/spec/rails_generators/shen_spec_generator_spec.rb +2 -2
  30. data/spec/rails_generators/shenandoah_generator_spec.rb +3 -3
  31. data/spec/shenandoah/server_spec.rb +156 -15
  32. metadata +32 -3
  33. data/lib/shenandoah/css/screw.css +0 -90
@@ -0,0 +1,87 @@
1
+ if (!window.shenandoah) { var shenandoah = {}; }
2
+
3
+ (function ($) {
4
+ shenandoah.Multirunner = function (container_id, spec_urls) {
5
+ ////// PRIVATE
6
+
7
+ var runner = this;
8
+
9
+ function container(subselector) {
10
+ var sel = "#" + runner.container_id;
11
+ if (subselector) sel += ' ' + subselector;
12
+ return jQuery(sel);
13
+ }
14
+
15
+ ////// PUBLIC
16
+
17
+ this.container_id = container_id;
18
+ this.spec_urls = spec_urls;
19
+
20
+ this.run = function () {
21
+ this.frames = container("#frames iframe").get();
22
+ this.next();
23
+ }
24
+
25
+ this.next = function () {
26
+ if (this.frames && this.frames.length > 0) {
27
+ setTimeout(function () { jQuery(runner.frames.shift()).trigger('begin') }, 0);
28
+ } else {
29
+ var show = container('#specs li.failed').get(0) || container('#specs li').get(0);
30
+ jQuery(show).trigger('activate');
31
+ }
32
+ }
33
+
34
+ this.reset = function () {
35
+ container().empty();
36
+ this.frames = null;
37
+ }
38
+
39
+ ////// INITIALIZATION
40
+
41
+ if (!this.spec_urls || this.spec_urls.length === 0) {
42
+ container().append("<p>No specs selected to run</p>")
43
+ } else {
44
+ container().append("<ul id='specs'></ul>").append("<div id='frames'></div>");
45
+ jQuery(this.spec_urls).each(function (idx) {
46
+ container("#specs").append('<li class="spec inactive"><span class="name">' + this.replace(/\/spec\//, "") + '</span>&nbsp;<span class="count"></span></li>');
47
+ container("#frames").append('<iframe class="inactive" spec-url="' + this + '" src="about:blank"></iframe>');
48
+ var newLi = container("#specs li:last-child");
49
+ var newFrame = container("#frames iframe:last-child");
50
+ var both = jQuery(newLi.selector + ", " + newFrame.selector);
51
+
52
+ both.bind('activate', function () {
53
+ both.removeClass('inactive').addClass('active');
54
+ }).bind('deactivate', function () {
55
+ both.addClass('inactive').removeClass('active');
56
+ });
57
+
58
+ newFrame.bind("begin", null, function (evt, data) {
59
+ newLi.find('.count').empty().end().trigger('activate');
60
+ newFrame.attr('src', newFrame.attr('spec-url'));
61
+ });
62
+
63
+ newFrame.bind("complete", null, function (evt, data) {
64
+ newLi.find('.count').text(data.passed_count + " of " + data.total_count).end().
65
+ removeClass('passed').removeClass('failed').addClass(data.passed_count === data.total_count ? 'passed' : 'failed').
66
+ trigger('deactivate');
67
+ runner.next();
68
+ });
69
+
70
+ newLi.bind('click', function () {
71
+ container('#frames iframe').trigger('deactivate');
72
+ newFrame.trigger('activate');
73
+ return false;
74
+ });
75
+ });
76
+ }
77
+ };
78
+
79
+ $(document).ready(function () {
80
+ var specs = jQuery.parseQuery().spec;
81
+ if (specs && specs.constructor !== Array) {
82
+ specs = [specs];
83
+ }
84
+ new shenandoah.Multirunner('runner', specs).run();
85
+ });
86
+
87
+ }(jQuery));
@@ -0,0 +1,19 @@
1
+ /**
2
+ * A simple querystring parser.
3
+ * Example usage: var q = $.parseQuery(); q.fooreturns "bar" if query contains "?foo=bar"; multiple values are added to an array.
4
+ * Values are unescaped by default and plus signs replaced with spaces, or an alternate processing function can be passed in the params object .
5
+ * http://actingthemaggot.com/jquery
6
+ *
7
+ * Copyright (c) 2008 Michael Manning (http://actingthemaggot.com)
8
+ * Dual licensed under the MIT (MIT-LICENSE.txt)
9
+ * and GPL (GPL-LICENSE.txt) licenses.
10
+ **/
11
+ jQuery.parseQuery = function(qs,options) {
12
+ var q = (typeof qs === 'string'?qs:window.location.search), o = {'f':function(v){return unescape(v).replace(/\+/g,' ');}}, options = (typeof qs === 'object' && typeof options === 'undefined')?qs:options, o = jQuery.extend({}, o, options), params = {};
13
+ jQuery.each(q.match(/^\??(.*)$/)[1].split('&'),function(i,p){
14
+ p = p.split('=');
15
+ p[1] = o.f(p[1]);
16
+ params[p[0]] = params[p[0]]?((params[p[0]] instanceof Array)?(params[p[0]].push(p[1]),params[p[0]]):[params[p[0]],p[1]]):p[1];
17
+ });
18
+ return params;
19
+ }
@@ -1,5 +1,7 @@
1
1
  require 'sinatra'
2
2
  require 'haml'
3
+ require 'sass'
4
+ require 'compass'
3
5
 
4
6
  module Shenandoah
5
7
  # The server which enables in-browser execution of Screw.Unit specs in
@@ -12,18 +14,23 @@ module Shenandoah
12
14
  class Server < Sinatra::Base
13
15
  set :root, File.dirname(__FILE__) + "/server"
14
16
  set :port, 4410
17
+ set :sass, Compass.sass_engine_options
15
18
  enable :logging
16
19
 
17
20
  get '/' do
18
21
  section_map = options.locator.spec_files.
19
22
  collect { |t| t.sub(%r{^#{options.locator.spec_path}/?}, '') }.
20
23
  collect { |t| [File.dirname(t), File.basename(t).sub(/_spec.js$/, '.html')] }.
21
- inject({}) { |h, (dir, file)| h[dir] ||= []; h[dir] << file; h }
24
+ inject({}) { |h, (dir, file)| h[dir] ||= []; h[dir] << IndexEntry.new(dir, file); h }
22
25
  @sections = section_map.collect { |dir, files| [dir, files.sort] }.sort
23
26
 
24
27
  haml :index
25
28
  end
26
29
 
30
+ get '/multirunner' do
31
+ haml :multirunner
32
+ end
33
+
27
34
  get '/main/*' do
28
35
  map_file(options.locator.main_path, params[:splat].first, "Main")
29
36
  end
@@ -32,27 +39,47 @@ module Shenandoah
32
39
  map_file(options.locator.spec_path, params[:splat].first, "Spec")
33
40
  end
34
41
 
35
- get '/screw.css' do
36
- screw_css = File.join(options.locator.spec_path, 'screw.css')
37
- unless File.exist?(screw_css)
38
- screw_css = File.join(File.dirname(__FILE__), 'css/screw.css')
42
+ get '/shenandoah.css' do
43
+ shenandoah_css = File.join(options.locator.spec_path, 'shenandoah.css')
44
+ if File.exist?(shenandoah_css)
45
+ send_file shenandoah_css
46
+ else
47
+ shenandoah_sass = File.join(options.locator.spec_path, 'shenandoah.sass')
48
+ unless File.exist?(shenandoah_sass)
49
+ shenandoah_sass = File.join(File.dirname(__FILE__), "css/shenandoah.sass")
50
+ end
51
+ content_type 'text/css'
52
+ last_modified File.stat(shenandoah_sass).mtime
53
+ sass File.read(shenandoah_sass)
39
54
  end
40
- send_file screw_css
55
+ end
56
+
57
+ get '/screw.css' do
58
+ uri = '/shenandoah.css'
59
+ $stderr.puts "DEPRECATION NOTICE: Use #{uri} instead of /screw.css."
60
+ status 301
61
+ response['Location'] = uri
62
+ "This URI is deprecated. Use <a href='#{uri}'>#{uri}</a>."
41
63
  end
42
64
 
43
65
  get '/shenandoah/browser-runner.js' do
66
+ maxtime, content = concatenate_files(runner_files)
67
+
44
68
  content_type 'text/javascript'
69
+ last_modified maxtime
70
+ content
71
+ end
45
72
 
46
- last_modified runner_files.collect { |filename|
47
- File.stat("#{File.dirname(__FILE__)}/#{filename}").mtime
48
- }.max
73
+ get '/shenandoah/multirunner.js' do
74
+ maxtime, content = concatenate_files(multirunner_files)
49
75
 
50
- runner_files.collect { |filename|
51
- [
52
- "\n//////\n////// #{filename}\n//////\n",
53
- File.read("#{File.dirname(__FILE__)}/#{filename}")
54
- ]
55
- }.flatten
76
+ content_type 'text/javascript'
77
+ last_modified maxtime
78
+ content
79
+ end
80
+
81
+ get '/js/*' do
82
+ send_file File.join(File.dirname(__FILE__), "javascript/#{params[:splat].first}")
56
83
  end
57
84
 
58
85
  protected
@@ -67,6 +94,21 @@ module Shenandoah
67
94
  end
68
95
  end
69
96
 
97
+ def concatenate_files(files)
98
+ maxtime = files.collect { |filename|
99
+ File.stat("#{File.dirname(__FILE__)}/#{filename}").mtime
100
+ }.max
101
+
102
+ content = files.collect { |filename|
103
+ [
104
+ "\n//////\n////// #{filename}\n//////\n",
105
+ File.read("#{File.dirname(__FILE__)}/#{filename}")
106
+ ]
107
+ }.flatten
108
+
109
+ [maxtime, content]
110
+ end
111
+
70
112
  def runner_files # :nodoc:
71
113
  # Can't just use Dir[] because order is important
72
114
  [
@@ -81,8 +123,31 @@ module Shenandoah
81
123
  "javascript/common/smoke.mock.js",
82
124
  "javascript/common/smoke.stub.js",
83
125
  "javascript/common/screw.mocking.js",
84
- "javascript/browser/runner.js"
126
+ "javascript/browser/runner.js",
127
+ "javascript/browser/multirunner-single.js"
85
128
  ]
86
129
  end
130
+
131
+ def multirunner_files # :nodoc
132
+ [
133
+ "javascript/common/jquery-1.3.2.js",
134
+ "javascript/common/jquery.parsequery.js",
135
+ "javascript/browser/multirunner.js"
136
+ ]
137
+ end
138
+
139
+ class IndexEntry < Struct.new(:section, :test_html)
140
+ def href
141
+ '/' + ["spec", section, test_html].reject { |s| s == '.' }.join('/')
142
+ end
143
+
144
+ def name
145
+ test_html.sub(/.html$/, '')
146
+ end
147
+
148
+ def <=>(other)
149
+ self.test_html <=> other.test_html
150
+ end
151
+ end
87
152
  end
88
153
  end
@@ -1,12 +1,22 @@
1
1
  %html
2
2
  %head
3
- %link{ :rel => "stylesheet", :href => "/screw.css", :type => "text/css", :charset => "utf-8" }
4
- %body
3
+ %script{ :src => '/js/common/jquery-1.3.2.js' }
4
+ %script{ :src => '/js/browser/index.js' }
5
+ %link{ :rel => "stylesheet", :href => "/shenandoah.css", :type => "text/css", :charset => "utf-8" }
6
+ %body#index
5
7
  - if options.respond_to?(:project_name) && options.project_name
6
8
  %h1= "Specs for #{options.project_name}"
7
- - @sections.each do |section, tests|
8
- %h2= section == '.' ? '[root]' : section
9
- %ul
10
- - tests.each do |test|
11
- %li
12
- %a{ :href => ["spec", section, test].reject { |s| s == '.' }.join('/') }= test.sub(/.html$/, '')
9
+ %label#select-all
10
+ %input{ :type => 'checkbox', :name => 'select-all' }
11
+ %a select all
12
+ %form{ :method => 'GET', :action => '/multirunner' }
13
+ - @sections.each do |section, tests|
14
+ %h2= section == '.' ? '[root]' : section
15
+ %ul
16
+ - tests.each do |test|
17
+ %li
18
+ %label
19
+ %input{ :type => 'checkbox', :name => 'spec', :value => test.href }
20
+ %a{ :href => test.href }= test.name
21
+ #controls
22
+ %input{ :type => 'submit', :value => 'Run selected' }
@@ -0,0 +1,6 @@
1
+ %html
2
+ %head
3
+ %script{ :src => '/shenandoah/multirunner.js', :type => 'text/javascript' }
4
+ %link{ :rel => 'stylesheet', :href => '/shenandoah.css' }
5
+ %body
6
+ #runner
@@ -3,7 +3,7 @@
3
3
 
4
4
  <head>
5
5
  <title><%= file_name %>.js | JavaScript Testing Results</title>
6
- <link rel="stylesheet" href="/screw.css" type="text/css" charset="utf-8" />
6
+ <link rel="stylesheet" href="/shenandoah.css" type="text/css" charset="utf-8" />
7
7
  <script type="text/javascript" src="/shenandoah/browser-runner.js"></script>
8
8
  </head>
9
9
 
@@ -3,7 +3,7 @@
3
3
 
4
4
  <head>
5
5
  <title>Application | JavaScript Testing Results</title>
6
- <link rel="stylesheet" href="/screw.css" type="text/css" charset="utf-8" />
6
+ <link rel="stylesheet" href="/shenandoah.css" type="text/css" charset="utf-8" />
7
7
  <script type="text/javascript" src="/shenandoah/browser-runner.js"></script>
8
8
  </head>
9
9
 
@@ -50,8 +50,8 @@ describe "shen_spec generator" do
50
50
  @html.should =~ %r{src="/shenandoah/browser-runner.js"}
51
51
  end
52
52
 
53
- it "includes screw.css" do
54
- @html.should =~ %r{href="/screw.css"}
53
+ it "includes shenandoah.css" do
54
+ @html.should =~ %r{href="/shenandoah.css"}
55
55
  end
56
56
  end
57
57
 
@@ -70,11 +70,11 @@ describe "shenandoah generator" do
70
70
  File.read(@path).should =~ %r{src="/shenandoah/browser-runner.js"}
71
71
  end
72
72
 
73
- it "links to the served screw.css" do
74
- File.read(@path).should =~ %r{href="/screw.css"}
73
+ it "links to the served shenandoah.css" do
74
+ File.read(@path).should =~ %r{href="/shenandoah.css"}
75
75
  end
76
76
  end
77
77
  end
78
78
  end
79
79
  end
80
- end
80
+ end
@@ -59,8 +59,13 @@ describe Shenandoah::Server do
59
59
  last_response.body.should =~ %r{function require_main\(}
60
60
  end
61
61
 
62
+ it "includes the multirunner code for a single test" do
63
+ last_response.body.should =~ %r{window.parent.jQuery\('iframe'\)}
64
+ end
65
+
62
66
  it "was last modified at the latest date of the combined files" do
63
67
  maxTime = Dir["#{File.dirname(__FILE__)}/../../lib/shenandoah/javascript/{browser,common}/*.js"].
68
+ reject { |filename| filename =~ /multirunner.js$/ || filename =~ /parsequery/i || filename =~ /index.js$/ }.
64
69
  collect { |filename| File.stat(filename).mtime }.max
65
70
  Time.httpdate(last_response.headers['Last-Modified']).should == maxTime
66
71
  end
@@ -114,37 +119,44 @@ describe Shenandoah::Server do
114
119
  end
115
120
  end
116
121
 
117
- describe "/screw.css" do
122
+ describe "/shenandoah.css" do
118
123
  describe "by default" do
119
124
  before do
120
- get '/screw.css'
121
- @included = "#{File.dirname(__FILE__)}/../../lib/shenandoah/css/screw.css"
125
+ get '/shenandoah.css'
126
+ @sass = File.expand_path(
127
+ "lib/shenandoah/css/shenandoah.sass", File.dirname(__FILE__) + "/../..")
122
128
  end
123
129
 
124
130
  it "is available" do
125
131
  last_response.should be_ok
126
132
  end
127
133
 
128
- it "is the included version" do
129
- last_response.body.should == File.read(@included)
134
+ it "is the CSS version of the included shenandoah.sass" do
135
+ last_response.body.should include('#frames iframe {')
136
+ last_response.body.should include('.describes .describe {')
137
+ end
138
+
139
+ it "includes the compass reset styles directly" do
140
+ last_response.body.should_not include("@import url(compass/reset.css)")
141
+ last_response.body.should include("table, caption, tbody, tfoot, thead, tr, th, td")
130
142
  end
131
143
 
132
144
  it "has the correct last modified version" do
133
145
  Time.httpdate(last_response.headers['Last-Modified']).should ==
134
- File.stat(@included).mtime
146
+ File.stat(@sass).mtime
135
147
  end
136
148
 
137
149
  it "is CSS" do
138
- last_response.headers['Content-Type'].should == 'text/css'
150
+ last_response.content_type.should == 'text/css'
139
151
  end
140
152
  end
141
153
 
142
- describe "when overridden" do
154
+ describe "when overridden with CSS" do
143
155
  before do
144
156
  app.set :locator,
145
157
  Shenandoah::DefaultLocator.new(:spec_path => self.tmpdir)
146
- tmpfile "screw.css", ".passed { color: blue }"
147
- get '/screw.css'
158
+ tmpfile "shenandoah.css", ".passed { color: blue }"
159
+ get '/shenandoah.css'
148
160
  end
149
161
 
150
162
  it "is available" do
@@ -157,13 +169,57 @@ describe Shenandoah::Server do
157
169
 
158
170
  it "has the correct last modified version" do
159
171
  Time.httpdate(last_response.headers['Last-Modified']).should ==
160
- File.stat("#{self.tmpdir}/screw.css").mtime
172
+ File.stat("#{self.tmpdir}/shenandoah.css").mtime
161
173
  end
162
174
 
163
175
  it "is CSS" do
164
- last_response.headers['Content-Type'].should == 'text/css'
176
+ last_response.content_type.should == 'text/css'
165
177
  end
166
178
  end
179
+
180
+ describe "when overridden with Sass" do
181
+ before do
182
+ app.set :locator,
183
+ Shenandoah::DefaultLocator.new(:spec_path => self.tmpdir)
184
+ tmpfile "shenandoah.sass", ".passed\n color: blue"
185
+ get '/shenandoah.css'
186
+ end
187
+
188
+ it "is available" do
189
+ last_response.should be_ok
190
+ end
191
+
192
+ it "is the version from the spec dir" do
193
+ last_response.body.should == ".passed {\n color: blue; }\n"
194
+ end
195
+
196
+ it "has the correct last modified version" do
197
+ Time.httpdate(last_response.headers['Last-Modified']).should ==
198
+ File.stat("#{self.tmpdir}/shenandoah.sass").mtime
199
+ end
200
+
201
+ it "is CSS" do
202
+ last_response.content_type.should == 'text/css'
203
+ end
204
+ end
205
+ end
206
+
207
+ describe "/screw.css" do
208
+ before do
209
+ get '/screw.css'
210
+ end
211
+
212
+ it "redirects" do
213
+ last_response.status.should == 301
214
+ end
215
+
216
+ it "points to /shenandoah.css" do
217
+ last_response['Location'].should == '/shenandoah.css'
218
+ end
219
+
220
+ it "includes a deprecation note" do
221
+ last_response.body.should == "This URI is deprecated. Use <a href='/shenandoah.css'>/shenandoah.css</a>."
222
+ end
167
223
  end
168
224
 
169
225
  describe "/" do
@@ -173,6 +229,7 @@ describe Shenandoah::Server do
173
229
  app.set :locator,
174
230
  Shenandoah::DefaultLocator.new(:spec_path => File.join(self.tmpdir, 'spec'))
175
231
  tmpfile "spec/common_spec.js", "DC"
232
+ tmpfile "spec/application_spec.js", "DC"
176
233
  tmpfile "spec/some/thing_spec.js", "DC"
177
234
  get "/"
178
235
  end
@@ -202,15 +259,99 @@ describe Shenandoah::Server do
202
259
  end
203
260
 
204
261
  it "includes lists of links" do
205
- last_response.body.should have_tag("ul a", :count => 2)
262
+ last_response.body.should have_tag("ul a", :count => 3)
206
263
  end
207
264
 
208
265
  it "includes a link to a spec in the root" do
209
- last_response.body.should have_tag("a[@href='spec/common.html']", "common")
266
+ last_response.body.should have_tag("a[@href='/spec/common.html']", "common")
210
267
  end
211
268
 
212
269
  it "includes link to a spec in a subdirectory" do
213
- last_response.body.should have_tag("a[@href='spec/some/thing.html']", "thing")
270
+ last_response.body.should have_tag("a[@href='/spec/some/thing.html']", "thing")
271
+ end
272
+
273
+ it "includes a checkbox for a spec in the root" do
274
+ last_response.body.should have_tag("input[@value='/spec/common.html']")
275
+ end
276
+
277
+ it "includes a checkbox for a spec in a subdirectory" do
278
+ last_response.body.should have_tag("input[@value='/spec/some/thing.html']")
279
+ end
280
+
281
+ it "includes a form to run the multirunner" do
282
+ last_response.body.should have_tag("form[@action='/multirunner']")
283
+ end
284
+
285
+ it "includes a submit button for the multirunner form" do
286
+ last_response.body.should have_tag("input[@type='submit']")
287
+ end
288
+ end
289
+
290
+ describe "/multirunner" do
291
+ include RspecHpricotMatchers
292
+
293
+ before do
294
+ get "/multirunner?spec=/spec/common.html"
295
+ end
296
+
297
+ it "is available" do
298
+ last_response.should be_ok
299
+ end
300
+
301
+ it "is html" do
302
+ last_response.content_type.should == 'text/html'
303
+ end
304
+
305
+ it "includes the multirunner script" do
306
+ last_response.body.should have_tag("script[@src='/shenandoah/multirunner.js']")
307
+ end
308
+
309
+ it "includes the container" do
310
+ last_response.body.should have_tag("div#runner")
311
+ end
312
+ end
313
+
314
+ describe "/shenandoah/multirunner.js" do
315
+ before do
316
+ get '/shenandoah/multirunner.js'
317
+ end
318
+
319
+ it "is available" do
320
+ last_response.should be_ok
321
+ end
322
+
323
+ it "is javascript" do
324
+ last_response.content_type.should == 'text/javascript'
325
+ end
326
+
327
+ it "contains the multirunner script" do
328
+ last_response.body.should =~ /shenandoah.Multirunner/
329
+ end
330
+
331
+ it "includes jQuery" do
332
+ last_response.body.should =~ %r{\* jQuery JavaScript Library v1\.3\.2}
333
+ end
334
+
335
+ it "includes parseQuery" do
336
+ last_response.body.should =~ %r{jQuery.parseQuery =}
337
+ end
338
+ end
339
+
340
+ describe "/js/common/jquery-1.3.2.js" do
341
+ before do
342
+ get '/js/common/jquery-1.3.2.js'
343
+ end
344
+
345
+ it "is available" do
346
+ last_response.should be_ok
347
+ end
348
+
349
+ it "is javascript" do
350
+ last_response.content_type.should == 'application/javascript'
351
+ end
352
+
353
+ it "includes jQuery" do
354
+ last_response.body.should =~ %r{\* jQuery JavaScript Library v1\.3\.2}
214
355
  end
215
356
  end
216
357
  end