screw_server 0.1.4

Sign up to get free protection for your applications and to get access to all the features.
Files changed (65) hide show
  1. data/Gemfile.run +3 -0
  2. data/Gemfile.run.lock +41 -0
  3. data/assets/screw-jslint.js +69 -0
  4. data/assets/screw-server.js +120 -0
  5. data/assets/screw.css +70 -0
  6. data/assets/vendor/fulljslint.js +5699 -0
  7. data/assets/vendor/screw-unit/CHANGES +7 -0
  8. data/assets/vendor/screw-unit/EXAMPLE.html +68 -0
  9. data/assets/vendor/screw-unit/LICENSE +22 -0
  10. data/assets/vendor/screw-unit/README.markdown +307 -0
  11. data/assets/vendor/screw-unit/example/models/cat.js +5 -0
  12. data/assets/vendor/screw-unit/example/models/man.js +17 -0
  13. data/assets/vendor/screw-unit/example/spec/matchers/have.js +8 -0
  14. data/assets/vendor/screw-unit/example/spec/models/cat_spec.js +31 -0
  15. data/assets/vendor/screw-unit/example/spec/models/man_spec.js +34 -0
  16. data/assets/vendor/screw-unit/example/spec/spec_helper.js +5 -0
  17. data/assets/vendor/screw-unit/example/spec/suite.html +25 -0
  18. data/assets/vendor/screw-unit/lib/jquery-1.2.6.js +3549 -0
  19. data/assets/vendor/screw-unit/lib/jquery.fn.js +29 -0
  20. data/assets/vendor/screw-unit/lib/jquery.print.js +109 -0
  21. data/assets/vendor/screw-unit/lib/screw.behaviors.js +101 -0
  22. data/assets/vendor/screw-unit/lib/screw.builder.js +90 -0
  23. data/assets/vendor/screw-unit/lib/screw.css +90 -0
  24. data/assets/vendor/screw-unit/lib/screw.events.js +45 -0
  25. data/assets/vendor/screw-unit/lib/screw.matchers.js +203 -0
  26. data/assets/vendor/screw-unit/spec/behaviors_spec.js +188 -0
  27. data/assets/vendor/screw-unit/spec/matchers_spec.js +391 -0
  28. data/assets/vendor/screw-unit/spec/print_spec.js +158 -0
  29. data/assets/vendor/screw-unit/spec/spec_helper.js +0 -0
  30. data/assets/vendor/screw-unit/spec/suite.html +18 -0
  31. data/assets/vendor/smoke/LICENSE +22 -0
  32. data/assets/vendor/smoke/README.markdown +68 -0
  33. data/assets/vendor/smoke/lib/smoke.core.js +49 -0
  34. data/assets/vendor/smoke/lib/smoke.mock.js +219 -0
  35. data/assets/vendor/smoke/lib/smoke.stub.js +29 -0
  36. data/assets/vendor/smoke/plugins/screw.mocking.js +26 -0
  37. data/assets/vendor/smoke/spec/core_spec.js +115 -0
  38. data/assets/vendor/smoke/spec/mock_spec.js +431 -0
  39. data/assets/vendor/smoke/spec/screw_integration_spec.js +17 -0
  40. data/assets/vendor/smoke/spec/spec_helper.js +0 -0
  41. data/assets/vendor/smoke/spec/stub_spec.js +17 -0
  42. data/assets/vendor/smoke/spec/su/jquery-1.2.3.js +3408 -0
  43. data/assets/vendor/smoke/spec/su/jquery.fn.js +29 -0
  44. data/assets/vendor/smoke/spec/su/jquery.print.js +108 -0
  45. data/assets/vendor/smoke/spec/su/screw.behaviors.js +91 -0
  46. data/assets/vendor/smoke/spec/su/screw.builder.js +80 -0
  47. data/assets/vendor/smoke/spec/su/screw.css +74 -0
  48. data/assets/vendor/smoke/spec/su/screw.events.js +38 -0
  49. data/assets/vendor/smoke/spec/su/screw.matchers.js +65 -0
  50. data/assets/vendor/smoke/spec/suite.html +29 -0
  51. data/bin/screw_server +43 -0
  52. data/lib/screw_server/app.rb +197 -0
  53. data/lib/screw_server/base.rb +21 -0
  54. data/lib/screw_server/fixture_file.rb +17 -0
  55. data/lib/screw_server/jslint_suite.rb +51 -0
  56. data/lib/screw_server/spec_file.rb +76 -0
  57. data/lib/screw_server.rb +2 -0
  58. data/screw_server.gemspec +28 -0
  59. data/views/index.haml +13 -0
  60. data/views/missing_spec_helper.haml +12 -0
  61. data/views/no_specs.haml +11 -0
  62. data/views/run_spec.haml +30 -0
  63. data/views/sample_spec.js +7 -0
  64. data/views/sample_spec_helper.js +2 -0
  65. metadata +257 -0
@@ -0,0 +1,197 @@
1
+ require 'sinatra/base'
2
+
3
+ require 'screw_server/jslint_suite'
4
+ require "screw_server/spec_file"
5
+
6
+ module ScrewServer
7
+ class App < Sinatra::Base
8
+
9
+ SPEC_BASE_URL = "___screw_specs___"
10
+ ASSET_BASE_URL = "___screw_assets___"
11
+ VIEW_PATH = File.join(File.dirname(__FILE__), "..", "..", "views")
12
+
13
+ set :views, VIEW_PATH
14
+
15
+ get "/run/:name" do
16
+ run_specs([SpecFile.new(params[:name])])
17
+ end
18
+
19
+ get "/run" do
20
+ run_specs(SpecFile.all)
21
+ end
22
+
23
+ get "/bisect/:victim/:begin/:end" do
24
+ victim = params[:victim]
25
+ suspects = SpecFile.all.map { |spec| spec.name } - [victim]
26
+
27
+ subset = suspects[params[:begin].to_i..(params[:end].to_i - 1)]
28
+
29
+ puts "suspects: #{subset.length}"
30
+
31
+ specs_to_run = (subset + [victim]).map {|name| SpecFile.new(name) }
32
+ run_specs(specs_to_run)
33
+ end
34
+
35
+ get "/" do
36
+ @specs = SpecFile.all
37
+ if @specs.empty?
38
+ render_setup_tutorial(:no_specs)
39
+ else
40
+ haml :index
41
+ end
42
+ end
43
+
44
+ get "/monitor" do
45
+ spec = SpecFile.latest
46
+ @include_monitor_code = true
47
+ run_specs([spec]);
48
+ end
49
+
50
+ get "/has_changes_since/:spec/:timestamp" do
51
+ if SpecFile.latest.name != params[:spec]
52
+ "true"
53
+ else
54
+ spec = SpecFile.new(params[:spec])
55
+ if spec.last_dependency_change > params[:timestamp].to_i
56
+ "true"
57
+ else
58
+ "false"
59
+ end
60
+ end
61
+ end
62
+
63
+ get "/#{SPEC_BASE_URL}/*" do
64
+ send_file(file_from_base_dir(Base.spec_base_dir, params[:splat]))
65
+ end
66
+
67
+ get "/#{ASSET_BASE_URL}/*" do
68
+ send_file(file_from_base_dir(asset_base_dir, params[:splat]))
69
+ end
70
+
71
+ helpers do
72
+ def cache_busting_url(url)
73
+ "#{url}?#{rand}"
74
+ end
75
+
76
+ def jslint_suites
77
+ jslint_file = File.join(Base.spec_base_dir, "jslint.rb")
78
+ if !File.exists?(jslint_file)
79
+ []
80
+ else
81
+ JslintSuite.suites_from(jslint_file).map do |suite|
82
+ {
83
+ :file_list => suite.file_list.map { |file| url_for_source_file(file) },
84
+ :options => suite.options_with_defaults
85
+ }
86
+ end
87
+ end
88
+ end
89
+
90
+ def url_for_screw_asset(file)
91
+ "/#{ASSET_BASE_URL}/#{file}"
92
+ end
93
+
94
+ def url_for_spec(file)
95
+ "/#{SPEC_BASE_URL}/#{file}"
96
+ end
97
+
98
+ def fixture_html
99
+ @specs.inject({}) { |result, spec| result.merge(spec.fixture_hash) }
100
+ end
101
+
102
+ def required_files
103
+ @specs.map(&:required_scripts).flatten.uniq
104
+ end
105
+
106
+ def monitor_code
107
+ spec = SpecFile.latest
108
+ <<-EOS
109
+ Screw.check_for_change = function() {
110
+ Screw.ajax({
111
+ url: "/has_changes_since/#{spec.name}/#{spec.last_dependency_change}",
112
+ cache: false,
113
+ success: function(answer) {
114
+ if (answer === "true") {
115
+ location.reload();
116
+ }
117
+ else {
118
+ setTimeout(Screw.check_for_change, 1000);
119
+ }
120
+ }
121
+ });
122
+ };
123
+ Screw.check_for_change();
124
+ EOS
125
+ end
126
+
127
+ def screw_assets
128
+ %w{
129
+ vendor/fulljslint.js
130
+ vendor/screw-unit/lib/jquery.fn.js
131
+ vendor/screw-unit/lib/jquery.print.js
132
+ vendor/screw-unit/lib/screw.builder.js
133
+ vendor/screw-unit/lib/screw.matchers.js
134
+ vendor/screw-unit/lib/screw.events.js
135
+ vendor/screw-unit/lib/screw.behaviors.js
136
+ vendor/smoke/lib/smoke.core.js
137
+ vendor/smoke/lib/smoke.mock.js
138
+ vendor/smoke/lib/smoke.stub.js
139
+ vendor/smoke/plugins/screw.mocking.js
140
+ screw-server.js
141
+ }
142
+ end
143
+
144
+ def sample_spec_file
145
+ "\n"+File.read(File.join(VIEW_PATH, "sample_spec.js"))
146
+ end
147
+
148
+ def sample_spec_helper
149
+ "\n"+File.read(File.join(VIEW_PATH, "sample_spec_helper.js"))
150
+ end
151
+ end
152
+
153
+ def self.run!(*args)
154
+ set(:public, Base.code_base_dir)
155
+ super(*args)
156
+ end
157
+
158
+ private
159
+
160
+ def file_from_base_dir(base_dir, file)
161
+ File.expand_path(File.join(base_dir, file)).tap do |result|
162
+ unless result.start_with?(base_dir)
163
+ raise Sinatra::NotFound, "Forbidden Access out of base directory"
164
+ end
165
+ end
166
+ end
167
+
168
+ def url_for_source_file(filename)
169
+ file = File.expand_path(filename)
170
+ if file.start_with?(Base.code_base_dir)
171
+ file[Base.code_base_dir.length..-1]
172
+ elsif file.start_with?(Base.spec_base_dir)
173
+ url_for_spec(file[(Base.spec_base_dir.length + 1)..-1])
174
+ else
175
+ raise "file #{file} cannot be checked by jslint since it it not inside the spec or code path"
176
+ end
177
+ end
178
+
179
+ def run_specs(specs)
180
+ if File.exists?(SpecFile.spec_helper_file)
181
+ @specs = specs
182
+ haml :run_spec
183
+ else
184
+ render_setup_tutorial(:missing_spec_helper)
185
+ end
186
+ end
187
+
188
+ def asset_base_dir
189
+ @assert_base_dir ||= File.expand_path(File.join(File.dirname(__FILE__), "..", "..", "assets"))
190
+ end
191
+
192
+ def render_setup_tutorial(template)
193
+ @spec_base_dir = Base.spec_base_dir
194
+ haml template
195
+ end
196
+ end
197
+ end
@@ -0,0 +1,21 @@
1
+ module ScrewServer
2
+ module Base
3
+ def self.spec_base_dir=(d)
4
+ raise "expected a directory with javascript specs under #{d}" unless File.exists?(d)
5
+ @spec_base_dir = d
6
+ end
7
+
8
+ def self.spec_base_dir
9
+ @spec_base_dir
10
+ end
11
+
12
+ def self.code_base_dir=(d)
13
+ raise "expected a directory with javascript code under #{d}" unless File.exists?(d)
14
+ @code_base_dir = d
15
+ end
16
+
17
+ def self.code_base_dir
18
+ @code_base_dir
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,17 @@
1
+ module ScrewServer
2
+ class FixtureFile
3
+ attr_reader :name
4
+
5
+ def self.base_dir
6
+ File.join(Base.spec_base_dir, "fixtures")
7
+ end
8
+
9
+ def initialize(name)
10
+ @name = name
11
+ end
12
+
13
+ def filename
14
+ "#{Base.spec_base_dir}/fixtures/#{name}.html"
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,51 @@
1
+ module ScrewServer
2
+ class JslintSuite
3
+
4
+ DEFAULT_OPTIONS = {
5
+ # true
6
+ "bitwise" => true,
7
+ "browser" => true,
8
+ "eqeqeq" => true,
9
+ "immed" => true,
10
+ "newcap" => true,
11
+ "nomen" => true,
12
+ "regexp" => true,
13
+ "undef" => true,
14
+ # false
15
+ "plusplus" => false,
16
+ "indent" => false,
17
+ "onevar" => false,
18
+ "white" => false,
19
+ "regexp" => false,
20
+ "nomen" => false
21
+ }
22
+
23
+ attr_accessor :name, :file_list, :options
24
+
25
+ def initialize(n)
26
+ @name = n
27
+ end
28
+
29
+ def file_list=(v)
30
+ @file_list = v.map { |file| File.expand_path(file) }
31
+ end
32
+
33
+ def self.suites_from(file)
34
+ @suites = []
35
+ eval(IO.read(file), binding, file)
36
+ @suites
37
+ end
38
+
39
+ def options_with_defaults
40
+ DEFAULT_OPTIONS.merge(self.options || {})
41
+ end
42
+
43
+ private
44
+
45
+ def self.jslint(name)
46
+ suite = JslintSuite.new(name)
47
+ yield suite
48
+ @suites << suite
49
+ end
50
+ end
51
+ end
@@ -0,0 +1,76 @@
1
+ require "screw_server/base"
2
+ require "screw_server/fixture_file"
3
+
4
+ module ScrewServer
5
+ class SpecFile
6
+ def self.all
7
+ Dir.glob(File.join(Base.spec_base_dir, "*_spec.js")).sort.map do |file|
8
+ SpecFile.new(file.gsub("#{Base.spec_base_dir}/", "").gsub("_spec.js", ""))
9
+ end
10
+ end
11
+
12
+ def self.latest
13
+ SpecFile.all.sort{ |a, b| a.last_changed <=> b.last_changed }.last
14
+ end
15
+
16
+ attr_reader :name
17
+
18
+ def initialize(name)
19
+ @name = name
20
+ end
21
+
22
+ def filename
23
+ File.join(Base.spec_base_dir, full_name)
24
+ end
25
+
26
+ def full_name
27
+ name + "_spec.js"
28
+ end
29
+
30
+ def used_fixtures
31
+ scan_for_statement("use_fixture", filename).map {|name| FixtureFile.new(name) }
32
+ end
33
+
34
+ def fixture_hash
35
+ used_fixtures.inject({}) do |result, fixture|
36
+ result.merge(fixture.name => File.read(fixture.filename))
37
+ end
38
+ end
39
+
40
+ def required_scripts
41
+ required_files_in(SpecFile.spec_helper_file) + required_files_in(filename)
42
+ end
43
+
44
+ def last_dependency_change
45
+ used_files.map do |file|
46
+ File.mtime(file).to_i rescue 0
47
+ end.max
48
+ end
49
+
50
+ def last_changed
51
+ @last_changed ||= File.mtime(filename).to_i
52
+ end
53
+
54
+ def used_files
55
+ [filename, SpecFile.spec_helper_file] +
56
+ used_fixtures.map(&:filename) +
57
+ required_scripts.map {|script| File.join(Base.code_base_dir, script)}
58
+ end
59
+
60
+ def self.spec_helper_file
61
+ File.join(Base.spec_base_dir, "spec_helper.js")
62
+ end
63
+
64
+ protected
65
+
66
+ def scan_for_statement(statement, filename)
67
+ File.read(filename).scan(/#{statement}\(["']\/?(.+)['"]\)/).map { |groups| groups[0] }
68
+ end
69
+
70
+ def required_files_in(filename)
71
+ files = scan_for_statement("require", filename)
72
+ files = files.reject { |file| file == "spec_helper.js" }
73
+ files = files.map { |file| file.gsub("../../public", "") }
74
+ end
75
+ end
76
+ end
@@ -0,0 +1,2 @@
1
+ require "screw_server/base"
2
+ require "screw_server/app"
@@ -0,0 +1,28 @@
1
+ Gem::Specification.new do |s|
2
+ s.name = %q{screw_server}
3
+ s.version = "0.1.4"
4
+ s.authors = ["Kristian Hanekamp", "Infopark AG"]
5
+ s.description = %q{Screw Server - easy javascript unit tests}
6
+ s.email = %q{kristian.hanekamp@infopark.de}
7
+ s.files =
8
+ Dir.glob("{lib,assets,views}/**/*") +
9
+ ["bin/screw_server", "Gemfile.run", "Gemfile.run.lock", "screw_server.gemspec"]
10
+ s.summary = %q{Screw Server}
11
+
12
+ s.add_dependency("json", "=1.4.3")
13
+ s.add_dependency("haml", "= 3.0.13")
14
+ s.add_dependency("bundler", "= 1.0.7")
15
+
16
+ # sinatra and dependencies
17
+ s.add_dependency("rack", "= 1.1.0")
18
+ s.add_dependency("sinatra", "= 1.0")
19
+
20
+ # thin and dependencies
21
+ s.add_dependency("daemons", "= 1.0.10")
22
+ # eventmachine 0.12.[7-10] has a bug when running without native extensions
23
+ # http://groups.google.com/group/eventmachine/browse_thread/thread/29fef72ee865ed6d
24
+ s.add_dependency("eventmachine", "= 0.12.6")
25
+ s.add_dependency("thin", "= 1.2.7")
26
+
27
+ s.executables = ['screw_server']
28
+ end
data/views/index.haml ADDED
@@ -0,0 +1,13 @@
1
+ %html
2
+ %head
3
+ %link{:rel => "stylesheet", :href => url_for_screw_asset("screw.css"), :type => "text/css"}
4
+
5
+ %body
6
+ %h1 Screw Server
7
+ %div{:style => "margin: 20px;"}
8
+ %div{:style => "margin: 20px;"}
9
+ %a{:href => "/run"} RUN ALL
10
+ %a{:href => "/monitor"} MONITOR
11
+ -@specs.each do |spec|
12
+ %li
13
+ %a{:href => "/run/#{spec.name}"}= spec.name
@@ -0,0 +1,12 @@
1
+ %html
2
+ %head
3
+ %link{:rel => "stylesheet", :href => url_for_screw_asset("screw.css"), :type => "text/css"}
4
+
5
+ %body
6
+ %p Cannot find #{@spec_base_dir}/spec_helper.js.
7
+ %br
8
+ %p Please create that file and use it for global test helpers.
9
+ %p Initially the file should at least require jQuery like this:
10
+ %br
11
+ %pre
12
+ = sample_spec_helper
@@ -0,0 +1,11 @@
1
+ %html
2
+ %head
3
+ %link{:rel => "stylesheet", :href => url_for_screw_asset("screw.css"), :type => "text/css"}
4
+
5
+ %body
6
+ %p The directory #{@spec_base_dir} does not contain any specs.
7
+ %br
8
+ %p Create a file #{@spec_base_dir}/foo_spec.js with the following content
9
+ %br
10
+ %pre
11
+ = sample_spec_file
@@ -0,0 +1,30 @@
1
+ %html
2
+ %head
3
+ %link{:rel => "stylesheet", :href => url_for_screw_asset("screw.css"), :type => "text/css"}
4
+
5
+ - required_files.each do |required_file|
6
+ %script{:type => "text/javascript", :src => cache_busting_url("/#{required_file}")}
7
+
8
+ - screw_assets.each do |asset|
9
+ %script{:type => "text/javascript", :src => url_for_screw_asset(asset)}
10
+
11
+ %script{:type => "text/javascript", :src => url_for_spec("spec_helper.js")}
12
+
13
+ %script{:type => "text/javascript"}
14
+ = "fixture_container = #{fixture_html.to_json}"
15
+ = "Screw.jslint_suites = #{jslint_suites.to_json};"
16
+ %body
17
+ %h3#screw_server_loading{:class => "status"}
18
+ Loading...
19
+ #fixture_container
20
+ - @specs.each do |spec|
21
+ %script{:type => "text/javascript", :src => cache_busting_url(url_for_spec(spec.full_name))}
22
+
23
+ %script{:type => "text/javascript", :src => url_for_screw_asset("screw-jslint.js")}
24
+
25
+ :javascript
26
+ $("#screw_server_loading").remove();
27
+
28
+ - if @include_monitor_code
29
+ %script{:type => "text/javascript"}
30
+ = monitor_code
@@ -0,0 +1,7 @@
1
+ Screw.Unit(function(){
2
+ describe("Simple Test", function() {
3
+ it("should be simple to write", function() {
4
+ expect(2 * 2).to(equal, 4);
5
+ });
6
+ });
7
+ });
@@ -0,0 +1,2 @@
1
+ // adjust the url below to match your application's jquery url
2
+ require("/javascripts/jquery.js");