screw-unit-server 0.3.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 (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