screw-unit-server 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (96) hide show
  1. data/CHANGES +5 -0
  2. data/README.markdown +347 -0
  3. data/Rakefile +70 -0
  4. data/bin/screw_unit +6 -0
  5. data/bin/screw_unit_server +10 -0
  6. data/core/EXAMPLE.html +68 -0
  7. data/core/LICENSE +22 -0
  8. data/core/README.markdown +307 -0
  9. data/core/TODO +2 -0
  10. data/core/example/models/cat.js +5 -0
  11. data/core/example/models/man.js +17 -0
  12. data/core/example/spec/matchers/have.js +8 -0
  13. data/core/example/spec/models/cat_spec.js +31 -0
  14. data/core/example/spec/models/man_spec.js +34 -0
  15. data/core/example/spec/spec_helper.js +5 -0
  16. data/core/example/spec/suite.html +25 -0
  17. data/core/lib/jquery-1.2.3.js +3408 -0
  18. data/core/lib/jquery.fn.js +29 -0
  19. data/core/lib/jquery.print.js +108 -0
  20. data/core/lib/screw.assets.js +36 -0
  21. data/core/lib/screw.behaviors.js +91 -0
  22. data/core/lib/screw.builder.js +80 -0
  23. data/core/lib/screw.css +90 -0
  24. data/core/lib/screw.events.js +38 -0
  25. data/core/lib/screw.matchers.js +65 -0
  26. data/core/lib/screw.server.js +21 -0
  27. data/core/spec/behaviors_spec.js +178 -0
  28. data/core/spec/matchers_spec.js +93 -0
  29. data/core/spec/print_spec.js +119 -0
  30. data/core/spec/spec_helper.js +0 -0
  31. data/core/spec/suite.html +18 -0
  32. data/init.rb +0 -0
  33. data/lib/screw_unit.rb +26 -0
  34. data/lib/screw_unit/resources.rb +2 -0
  35. data/lib/screw_unit/resources/spec.rb +37 -0
  36. data/spec/functional/functional_spec.rb +14 -0
  37. data/spec/functional/functional_spec_helper.rb +55 -0
  38. data/spec/functional_suite.rb +10 -0
  39. data/spec/spec_suite.rb +3 -0
  40. data/spec/unit/js_test_core/specs/spec_dir_spec.rb +43 -0
  41. data/spec/unit/js_test_core/specs/spec_file_spec.rb +43 -0
  42. data/spec/unit/unit_spec_helper.rb +120 -0
  43. data/spec/unit_suite.rb +10 -0
  44. data/vendor/js-test-core/CHANGES +9 -0
  45. data/vendor/js-test-core/README +12 -0
  46. data/vendor/js-test-core/Rakefile +72 -0
  47. data/vendor/js-test-core/lib/js_test_core.rb +30 -0
  48. data/vendor/js-test-core/lib/js_test_core/client.rb +50 -0
  49. data/vendor/js-test-core/lib/js_test_core/rack.rb +2 -0
  50. data/vendor/js-test-core/lib/js_test_core/rack/commonlogger.rb +5 -0
  51. data/vendor/js-test-core/lib/js_test_core/rails_server.rb +22 -0
  52. data/vendor/js-test-core/lib/js_test_core/resources.rb +11 -0
  53. data/vendor/js-test-core/lib/js_test_core/resources/dir.rb +52 -0
  54. data/vendor/js-test-core/lib/js_test_core/resources/file.rb +32 -0
  55. data/vendor/js-test-core/lib/js_test_core/resources/file_not_found.rb +15 -0
  56. data/vendor/js-test-core/lib/js_test_core/resources/runners.rb +15 -0
  57. data/vendor/js-test-core/lib/js_test_core/resources/runners/firefox_runner.rb +75 -0
  58. data/vendor/js-test-core/lib/js_test_core/resources/specs/spec_dir.rb +50 -0
  59. data/vendor/js-test-core/lib/js_test_core/resources/specs/spec_file.rb +17 -0
  60. data/vendor/js-test-core/lib/js_test_core/resources/suite.rb +24 -0
  61. data/vendor/js-test-core/lib/js_test_core/resources/suite_finish.rb +19 -0
  62. data/vendor/js-test-core/lib/js_test_core/resources/web_root.rb +62 -0
  63. data/vendor/js-test-core/lib/js_test_core/selenium.rb +2 -0
  64. data/vendor/js-test-core/lib/js_test_core/selenium/selenium_driver.rb +5 -0
  65. data/vendor/js-test-core/lib/js_test_core/server.rb +111 -0
  66. data/vendor/js-test-core/lib/js_test_core/thin.rb +3 -0
  67. data/vendor/js-test-core/lib/js_test_core/thin/backends/js_test_core_server.rb +9 -0
  68. data/vendor/js-test-core/lib/js_test_core/thin/js_test_core_connection.rb +42 -0
  69. data/vendor/js-test-core/spec/example_core/JsTestCore.css +0 -0
  70. data/vendor/js-test-core/spec/example_core/JsTestCore.js +0 -0
  71. data/vendor/js-test-core/spec/example_public/favicon.ico +0 -0
  72. data/vendor/js-test-core/spec/example_public/javascripts/foo.js +3 -0
  73. data/vendor/js-test-core/spec/example_public/robots.txt +0 -0
  74. data/vendor/js-test-core/spec/example_public/stylesheets/example.css +3 -0
  75. data/vendor/js-test-core/spec/example_specs/failing_spec.js +5 -0
  76. data/vendor/js-test-core/spec/example_specs/foo/failing_spec.js +6 -0
  77. data/vendor/js-test-core/spec/example_specs/foo/passing_spec.js +6 -0
  78. data/vendor/js-test-core/spec/spec_suite.rb +2 -0
  79. data/vendor/js-test-core/spec/specs/failing_spec.js +0 -0
  80. data/vendor/js-test-core/spec/unit/js_test_core/client_spec.rb +137 -0
  81. data/vendor/js-test-core/spec/unit/js_test_core/rails_server_spec.rb +45 -0
  82. data/vendor/js-test-core/spec/unit/js_test_core/resources/dir_spec.rb +42 -0
  83. data/vendor/js-test-core/spec/unit/js_test_core/resources/file_not_found_spec.rb +26 -0
  84. data/vendor/js-test-core/spec/unit/js_test_core/resources/file_spec.rb +88 -0
  85. data/vendor/js-test-core/spec/unit/js_test_core/resources/runner_spec.rb +24 -0
  86. data/vendor/js-test-core/spec/unit/js_test_core/resources/runners/firefox_runner_spec.rb +197 -0
  87. data/vendor/js-test-core/spec/unit/js_test_core/resources/specs/spec_dir_spec.rb +79 -0
  88. data/vendor/js-test-core/spec/unit/js_test_core/resources/specs/spec_file_spec.rb +42 -0
  89. data/vendor/js-test-core/spec/unit/js_test_core/resources/suite_finish_spec.rb +94 -0
  90. data/vendor/js-test-core/spec/unit/js_test_core/resources/suite_spec.rb +44 -0
  91. data/vendor/js-test-core/spec/unit/js_test_core/resources/web_root_spec.rb +103 -0
  92. data/vendor/js-test-core/spec/unit/js_test_core/server_spec.rb +131 -0
  93. data/vendor/js-test-core/spec/unit/thin/js_test_core_connection_spec.rb +92 -0
  94. data/vendor/js-test-core/spec/unit/unit_spec_helper.rb +125 -0
  95. data/vendor/js-test-core/spec/unit_suite.rb +10 -0
  96. metadata +186 -0
@@ -0,0 +1,30 @@
1
+ require "rubygems"
2
+ gem "thin", ">=0.8.0"
3
+
4
+ require "thin"
5
+ require "fileutils"
6
+ require "tmpdir"
7
+ require "timeout"
8
+ require "cgi"
9
+ require "net/http"
10
+ require "selenium"
11
+ require "optparse"
12
+
13
+ dir = File.dirname(__FILE__)
14
+ require "#{dir}/js_test_core/thin"
15
+ require "#{dir}/js_test_core/rack"
16
+ require "#{dir}/js_test_core/resources"
17
+ require "#{dir}/js_test_core/selenium"
18
+
19
+ require "#{dir}/js_test_core/client"
20
+ require "#{dir}/js_test_core/server"
21
+ require "#{dir}/js_test_core/rails_server"
22
+
23
+ module JsTestCore
24
+ DEFAULT_HOST = "0.0.0.0"
25
+ DEFAULT_PORT = 8080
26
+
27
+ class << self
28
+ attr_accessor :core_path
29
+ end
30
+ end
@@ -0,0 +1,50 @@
1
+ module JsTestCore
2
+ class Client
3
+ class << self
4
+ def run(params={})
5
+ data = []
6
+ data << "selenium_host=#{CGI.escape(params[:selenium_host] || 'localhost')}"
7
+ data << "selenium_port=#{CGI.escape((params[:selenium_port] || 4444).to_s)}"
8
+ data << "spec_url=#{CGI.escape(params[:spec_url])}" if params[:spec_url]
9
+ response = Net::HTTP.start(DEFAULT_HOST, DEFAULT_PORT) do |http|
10
+ http.post('/runners/firefox', data.join("&"))
11
+ end
12
+
13
+ body = response.body
14
+ if body.empty?
15
+ puts "SUCCESS"
16
+ return true
17
+ else
18
+ puts "FAILURE"
19
+ puts body
20
+ return false
21
+ end
22
+ end
23
+
24
+ def run_argv(argv)
25
+ params = {}
26
+ parser = OptionParser.new do |o|
27
+ o.banner = "JsTestCore Runner"
28
+ o.banner << "\nUsage: #{$0} [options] [-- untouched arguments]"
29
+
30
+ o.on
31
+ o.on('-h', '--selenium_host=SELENIUM_HOST', "The host name of the Selenium Server relative to where this file is executed") do |host|
32
+ params[:selenium_host] = host
33
+ end
34
+
35
+ o.on('-p', '--selenium_port=SELENIUM_PORT', "The port of the Selenium Server relative to where this file is executed") do |port|
36
+ params[:selenium_port] = port
37
+ end
38
+
39
+ o.on('-u', '--spec_url=SPEC_URL', "The url of the js spec server, relative to the browsers running via the Selenium Server") do |spec_url|
40
+ params[:spec_url] = spec_url
41
+ end
42
+
43
+ o.on_tail
44
+ end
45
+ parser.order!(argv)
46
+ run params
47
+ end
48
+ end
49
+ end
50
+ end
@@ -0,0 +1,2 @@
1
+ dir = File.dirname(__FILE__)
2
+ require "#{dir}/rack/commonlogger"
@@ -0,0 +1,5 @@
1
+ Rack::CommonLogger.class_eval do
2
+ def empty?
3
+ @body.empty?
4
+ end
5
+ end
@@ -0,0 +1,22 @@
1
+ module JsTestCore
2
+ class RailsServer < Server
3
+ class << self
4
+ def run(rails_root, server_options = {})
5
+ server_options[:Host] ||= DEFAULT_HOST
6
+ server_options[:Port] ||= DEFAULT_PORT
7
+ Server.instance = new(rails_root, server_options[:Host], server_options[:Port])
8
+ Server.instance.run server_options
9
+ end
10
+ end
11
+
12
+ def initialize(rails_root, host=DEFAULT_HOST, port=DEFAULT_PORT)
13
+ super(
14
+ "#{rails_root}/spec/javascripts",
15
+ "#{rails_root}/public/javascripts",
16
+ "#{rails_root}/public",
17
+ host,
18
+ port
19
+ )
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,11 @@
1
+ dir = File.dirname(__FILE__)
2
+ require "#{dir}/resources/runners"
3
+ require "#{dir}/resources/runners/firefox_runner"
4
+ require "#{dir}/resources/file"
5
+ require "#{dir}/resources/dir"
6
+ require "#{dir}/resources/file_not_found"
7
+ require "#{dir}/resources/specs/spec_file"
8
+ require "#{dir}/resources/specs/spec_dir"
9
+ require "#{dir}/resources/web_root"
10
+ require "#{dir}/resources/suite"
11
+ require "#{dir}/resources/suite_finish"
@@ -0,0 +1,52 @@
1
+ module JsTestCore
2
+ module Resources
3
+ class Dir < File
4
+ def locate(name)
5
+ if file = file(name)
6
+ file
7
+ elsif subdir = subdir(name)
8
+ subdir
9
+ else
10
+ raise "No file or directory found at #{relative_path}/#{name}."
11
+ end
12
+ end
13
+
14
+ def get(request, response)
15
+
16
+ end
17
+
18
+ def glob(pattern)
19
+ expanded_pattern = absolute_path + pattern
20
+ ::Dir.glob(expanded_pattern).map do |absolute_globbed_path|
21
+ relative_globbed_path = absolute_globbed_path.gsub(absolute_path, relative_path)
22
+ File.new(absolute_globbed_path, relative_globbed_path)
23
+ end
24
+ end
25
+
26
+ protected
27
+ def determine_child_paths(name)
28
+ absolute_child_path = "#{absolute_path}/#{name}"
29
+ relative_child_path = "#{relative_path}/#{name}"
30
+ [absolute_child_path, relative_child_path]
31
+ end
32
+
33
+ def file(name)
34
+ absolute_file_path, relative_file_path = determine_child_paths(name)
35
+ if ::File.exists?(absolute_file_path) && !::File.directory?(absolute_file_path)
36
+ Resources::File.new(absolute_file_path, relative_file_path)
37
+ else
38
+ nil
39
+ end
40
+ end
41
+
42
+ def subdir(name)
43
+ absolute_dir_path, relative_dir_path = determine_child_paths(name)
44
+ if ::File.directory?(absolute_dir_path)
45
+ Resources::Dir.new(absolute_dir_path, relative_dir_path)
46
+ else
47
+ nil
48
+ end
49
+ end
50
+ end
51
+ end
52
+ end
@@ -0,0 +1,32 @@
1
+ module JsTestCore
2
+ module Resources
3
+ class File
4
+ MIME_TYPES = {
5
+ '.js' => 'text/javascript',
6
+ '.css' => 'text/css',
7
+ '.png' => 'image/png',
8
+ '.jpg' => 'image/jpeg',
9
+ '.jpeg' => 'image/jpeg',
10
+ '.gif' => 'image/gif',
11
+ }
12
+
13
+ attr_reader :absolute_path, :relative_path
14
+
15
+ def initialize(absolute_path, relative_path)
16
+ @absolute_path = absolute_path
17
+ @relative_path = relative_path
18
+ end
19
+
20
+ def get(request, response)
21
+ extension = ::File.extname(absolute_path)
22
+ response.headers['Content-Type'] = MIME_TYPES[extension] || 'text/html'
23
+ response.body = ::File.read(absolute_path)
24
+ end
25
+
26
+ def ==(other)
27
+ return false unless other.class == self.class
28
+ absolute_path == other.absolute_path && relative_path == other.relative_path
29
+ end
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,15 @@
1
+ module JsTestCore
2
+ module Resources
3
+ class FileNotFound
4
+ attr_reader :name
5
+ def initialize(name)
6
+ @name = name
7
+ end
8
+
9
+ def get(request, response)
10
+ response.status = 404
11
+ response.body = "Path #{name} not found. You may want to try the /#{WebRoot.dispatch_strategy} directory."
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,15 @@
1
+ dir = File.dirname(__FILE__)
2
+
3
+ module JsTestCore
4
+ module Resources
5
+ class Runners
6
+ def locate(name)
7
+ if name == 'firefox'
8
+ FirefoxRunner.new
9
+ else
10
+ raise "Invalid path #{name}"
11
+ end
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,75 @@
1
+ module JsTestCore
2
+ module Resources
3
+ class Runners
4
+ class FirefoxRunner
5
+ class << self
6
+ def resume(suite_id, text)
7
+ if instances[suite_id]
8
+ runner = instances.delete(suite_id)
9
+ runner.finalize(text)
10
+ end
11
+ end
12
+
13
+ def register_instance(runner)
14
+ instances[runner.suite_id] = runner
15
+ end
16
+
17
+ protected
18
+ def instances
19
+ @instances ||= {}
20
+ end
21
+ end
22
+
23
+ include FileUtils
24
+ attr_reader :profile_dir, :connection, :driver, :response
25
+
26
+ def initialize
27
+ profile_base = "#{::Dir.tmpdir}/js_test_core/firefox"
28
+ mkdir_p profile_base
29
+ @profile_dir = "#{profile_base}/#{Time.now.to_i}"
30
+ @connection = Server.connection
31
+ end
32
+
33
+ def post(request, response)
34
+ @response = response
35
+
36
+ spec_url = (request && request['spec_url']) ? request['spec_url'] : spec_suite_url
37
+ parsed_spec_url = URI.parse(spec_url)
38
+ selenium_port = (request['selenium_port'] || 4444).to_i
39
+ @driver = Selenium::SeleniumDriver.new(
40
+ request['selenium_host'] || 'localhost',
41
+ selenium_port,
42
+ '*firefox',
43
+ "#{parsed_spec_url.scheme}://#{parsed_spec_url.host}:#{parsed_spec_url.port}"
44
+ )
45
+ begin
46
+ driver.start
47
+ rescue Errno::ECONNREFUSED => e
48
+ raise Errno::ECONNREFUSED, "Cannot connect to Selenium Server on port #{selenium_port}. To start the selenium server, run `selenium`."
49
+ end
50
+ Thread.start do
51
+ driver.open(spec_url)
52
+ end
53
+ response.status = 200
54
+ FirefoxRunner.register_instance self
55
+ end
56
+
57
+ def finalize(text)
58
+ driver.stop
59
+ response.body = text
60
+ connection.send_body(response)
61
+ end
62
+
63
+ def suite_id
64
+ driver.session_id
65
+ end
66
+
67
+ protected
68
+
69
+ def spec_suite_url
70
+ "#{Server.root_url}/specs"
71
+ end
72
+ end
73
+ end
74
+ end
75
+ end
@@ -0,0 +1,50 @@
1
+ module JsTestCore
2
+ module Resources
3
+ module Specs
4
+ class SpecDirSuperclass < ::JsTestCore::Resources::Dir
5
+ def get(request, response)
6
+ raise NotImplementedError, "#{self.class}#get needs to be implemented"
7
+ end
8
+ end
9
+
10
+ class SpecDir < SpecDirSuperclass
11
+ def spec_files
12
+ glob("/**/*_spec.js")
13
+ end
14
+
15
+ def locate(name)
16
+ if file = file(name)
17
+ file
18
+ elsif subdir = subdir(name)
19
+ subdir
20
+ elsif spec_file = spec_file(name)
21
+ spec_file
22
+ else
23
+ base_path = "#{relative_path}/#{name}"
24
+ raise "No file or directory found at #{base_path} or spec found at #{base_path}.js."
25
+ end
26
+ end
27
+
28
+ protected
29
+
30
+ def subdir(name)
31
+ absolute_dir_path, relative_dir_path = determine_child_paths(name)
32
+ if ::File.directory?(absolute_dir_path)
33
+ SpecDir.new(absolute_dir_path, relative_dir_path)
34
+ else
35
+ nil
36
+ end
37
+ end
38
+
39
+ def spec_file(name)
40
+ absolute_file_path, relative_file_path = determine_child_paths("#{name}.js")
41
+ if ::File.exists?(absolute_file_path) && !::File.directory?(absolute_file_path)
42
+ SpecFile.new(absolute_file_path, relative_file_path)
43
+ else
44
+ nil
45
+ end
46
+ end
47
+ end
48
+ end
49
+ end
50
+ end
@@ -0,0 +1,17 @@
1
+ module JsTestCore
2
+ module Resources
3
+ module Specs
4
+ class SpecFileSuperclass < ::JsTestCore::Resources::File
5
+ def get(request, response)
6
+ raise NotImplementedError, "#{self.class}#get needs to be implemented"
7
+ end
8
+ end
9
+
10
+ class SpecFile < SpecFileSuperclass
11
+ def spec_files
12
+ [self]
13
+ end
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,24 @@
1
+ module JsTestCore
2
+ module Resources
3
+ class Suite
4
+ class << self
5
+ def locate(id)
6
+ new id
7
+ end
8
+ end
9
+
10
+ attr_reader :id
11
+ def initialize(id)
12
+ @id = id
13
+ end
14
+
15
+ def locate(name)
16
+ if name == 'finish'
17
+ SuiteFinish.new self
18
+ else
19
+ raise ArgumentError, "Invalid path: #{name}"
20
+ end
21
+ end
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,19 @@
1
+ module JsTestCore
2
+ module Resources
3
+ class SuiteFinish
4
+ attr_reader :suite
5
+ def initialize(suite)
6
+ @suite = suite
7
+ end
8
+
9
+ def post(request, response)
10
+ if suite.id == 'user'
11
+ STDOUT.puts request['text']
12
+ else
13
+ Runners::FirefoxRunner.resume(suite.id, request['text'])
14
+ end
15
+ response.headers['Content-Length'] = "0"
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,62 @@
1
+ module JsTestCore
2
+ module Resources
3
+ class WebRoot
4
+ LOCATIONS = [
5
+ ['', lambda do |web_root|
6
+ web_root
7
+ end],
8
+ ['core', lambda do
9
+ Resources::Dir.new(JsTestCore::Server.core_path, "/core")
10
+ end],
11
+ ['implementations', lambda do
12
+ Resources::Dir.new(JsTestCore::Server.implementation_root_path, "/implementations")
13
+ end],
14
+ ['suites', lambda do
15
+ Resources::Suite
16
+ end],
17
+ ['runners', lambda do
18
+ Resources::Runners.new
19
+ end]
20
+ ]
21
+
22
+ class << self
23
+ attr_accessor :dispatch_strategy
24
+ def dispatch_specs
25
+ self.dispatch_strategy = :specs
26
+ end
27
+ end
28
+
29
+ attr_reader :public_path
30
+ def initialize(public_path)
31
+ @public_path = ::File.expand_path(public_path)
32
+ end
33
+
34
+ def locate(name)
35
+ if self.class.dispatch_strategy == :specs && name == 'specs'
36
+ return JsTestCore::Resources::Specs::SpecDir.new(JsTestCore::Server.spec_root_path, "/specs")
37
+ end
38
+
39
+ location, initializer = LOCATIONS.find do |location|
40
+ location.first == name
41
+ end
42
+ if initializer
43
+ initializer.call(self)
44
+ else
45
+ potential_file_in_public_path = "#{public_path}/#{name}"
46
+ if ::File.directory?(potential_file_in_public_path)
47
+ Resources::Dir.new(potential_file_in_public_path, "/#{name}")
48
+ elsif ::File.exists?(potential_file_in_public_path)
49
+ Resources::File.new(potential_file_in_public_path, "/#{name}")
50
+ else
51
+ Resources::FileNotFound.new(name)
52
+ end
53
+ end
54
+ end
55
+
56
+ def get(request, response)
57
+ response.status = 301
58
+ response['Location'] = "/#{self.class.dispatch_strategy}"
59
+ end
60
+ end
61
+ end
62
+ end