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,94 @@
1
+ require File.expand_path("#{File.dirname(__FILE__)}/../../unit_spec_helper")
2
+
3
+ module JsTestCore
4
+ module Resources
5
+ describe SuiteFinish do
6
+ attr_reader :stdout, :suite_finish, :suite
7
+ before do
8
+ @stdout = StringIO.new
9
+ SuiteFinish.const_set(:STDOUT, stdout)
10
+ end
11
+
12
+ after do
13
+ SuiteFinish.__send__(:remove_const, :STDOUT)
14
+ end
15
+
16
+ describe ".post" do
17
+ describe "when Suite#id == 'user'" do
18
+ before do
19
+ @suite = Suite.new('user')
20
+ @suite_finish = SuiteFinish.new(suite)
21
+ end
22
+
23
+ it "writes the body of the request to stdout" do
24
+ body = "The text in the POST body"
25
+ request = Rack::Request.new({'rack.input' => StringIO.new("text=#{body}")})
26
+ request.body.string.should == "text=#{body}"
27
+ response = Rack::Response.new
28
+
29
+ suite_finish.post(request, response)
30
+ stdout.string.should == "#{body}\n"
31
+ end
32
+
33
+ it "sets the Content-Length to be 0" do
34
+ request = Rack::Request.new('rack.input' => StringIO.new(""))
35
+ response = Rack::Response.new
36
+
37
+ response.headers["Content-Length"].should be_nil
38
+ suite_finish.post(request, response)
39
+ response.headers["Content-Length"].should == "0"
40
+ end
41
+ end
42
+
43
+ describe "when Suite#id is not 'user'" do
44
+ attr_reader :request, :response, :runner, :suite_id, :driver
45
+ before do
46
+ runner_request = Rack::Request.new( Rack::MockRequest.env_for('/runners/firefox') )
47
+ runner_response = Rack::Response.new
48
+ @suite_id = '12345'
49
+ @driver = "Selenium Driver"
50
+ stub(Selenium::SeleniumDriver).new('localhost', 4444, '*firefox', 'http://0.0.0.0:8080') do
51
+ driver
52
+ end
53
+ stub(driver).start
54
+ stub(driver).open
55
+ stub(driver).session_id {suite_id}
56
+ stub(Thread).start.yields
57
+ Thread.current[:connection] = connection
58
+
59
+ @runner = Runners::FirefoxRunner.new
60
+ runner.post(runner_request, runner_response)
61
+
62
+ @suite = Suite.new(suite_id)
63
+ @suite_finish = SuiteFinish.new(suite)
64
+ end
65
+
66
+ it "resumes the FirefoxRunner" do
67
+ body = "The text in the POST body"
68
+ request = Rack::Request.new({'rack.input' => StringIO.new("text=#{body}")})
69
+ response = Rack::Response.new
70
+ mock.proxy(Runners::FirefoxRunner).resume(suite_id, body)
71
+ mock(driver).stop
72
+ stub(connection).send_data.once
73
+ stub(connection).close_connection.once
74
+
75
+ suite_finish.post(request, response)
76
+ end
77
+
78
+ it "sets the Content-Length to be 0" do
79
+ request = Rack::Request.new('rack.input' => StringIO.new(""))
80
+ response = Rack::Response.new
81
+ stub(Runners::FirefoxRunner).resume
82
+ stub(driver).stop
83
+ stub(connection).send_data
84
+ stub(connection).close_connection
85
+
86
+ response.headers["Content-Length"].should be_nil
87
+ suite_finish.post(request, response)
88
+ response.headers["Content-Length"].should == "0"
89
+ end
90
+ end
91
+ end
92
+ end
93
+ end
94
+ end
@@ -0,0 +1,44 @@
1
+ require File.expand_path("#{File.dirname(__FILE__)}/../../unit_spec_helper")
2
+
3
+ module JsTestCore
4
+ module Resources
5
+ describe Suite do
6
+ attr_reader :stdout
7
+ before do
8
+ @stdout = StringIO.new
9
+ Suite.const_set(:STDOUT, stdout)
10
+ end
11
+
12
+ after do
13
+ Suite.__send__(:remove_const, :STDOUT)
14
+ end
15
+
16
+ describe ".locate" do
17
+ it "when passed an identifier, returns an instance of Suite with the identifier" do
18
+ instance = Suite.locate('foobar')
19
+ instance.class.should == Suite
20
+ instance.id.should == 'foobar'
21
+ end
22
+ end
23
+
24
+ describe "#locate" do
25
+ attr_reader :suite
26
+ before do
27
+ @suite = Suite.new('foobar')
28
+ end
29
+
30
+ it "when passed 'finish', returns a SuiteFinish that has access to the suite" do
31
+ suite_finish = suite.locate('finish')
32
+ suite_finish.class.should == SuiteFinish
33
+ suite_finish.suite.should == suite
34
+ end
35
+
36
+ it "when not passed 'finish', raises ArgumentError" do
37
+ lambda do
38
+ suite.locate('invalid')
39
+ end.should raise_error(ArgumentError, "Invalid path: invalid")
40
+ end
41
+ end
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,103 @@
1
+ require File.expand_path("#{File.dirname(__FILE__)}/../../unit_spec_helper")
2
+
3
+ module JsTestCore
4
+ module Resources
5
+ describe WebRoot do
6
+ attr_reader :web_root
7
+ before(:each) do
8
+ @web_root = WebRoot.new(public_path)
9
+ end
10
+
11
+ describe "#locate" do
12
+ describe "when passed ''" do
13
+ it "returns self" do
14
+ web_root.locate('').should == web_root
15
+ end
16
+ end
17
+
18
+ describe "when passed 'core'" do
19
+ it "returns a Dir representing the JsTestCore core directory" do
20
+ runner = web_root.locate('core')
21
+ runner.should == Resources::Dir.new(JsTestCore::Server.core_path, '/core')
22
+ end
23
+ end
24
+
25
+ describe "when passed 'implementations'" do
26
+ it "returns a Dir representing the javascript implementations directory" do
27
+ runner = web_root.locate('implementations')
28
+ runner.should == Resources::Dir.new(JsTestCore::Server.implementation_root_path, '/implementations')
29
+ end
30
+ end
31
+
32
+ describe "when passed 'results'" do
33
+ it "returns a Suite" do
34
+ runner = web_root.locate('suites')
35
+ runner.should == Resources::Suite
36
+ end
37
+ end
38
+
39
+ describe "when passed 'runners'" do
40
+ it "returns a Runner" do
41
+ runner = web_root.locate('runners')
42
+ runner.should be_instance_of(Resources::Runners)
43
+ end
44
+ end
45
+
46
+ describe "when passed a directory that is in the public_path" do
47
+ it "returns a Dir representing that directory" do
48
+ runner = web_root.locate('stylesheets')
49
+ runner.should == Resources::Dir.new("#{JsTestCore::Server.public_path}/stylesheets", '/stylesheets')
50
+ end
51
+ end
52
+
53
+ describe "when passed a file that is in the public_path" do
54
+ it "returns a File representing that file" do
55
+ runner = web_root.locate('robots.txt')
56
+ runner.should == Resources::File.new("#{JsTestCore::Server.public_path}/robots.txt", '/robots.txt')
57
+ end
58
+ end
59
+
60
+ describe "when passed an invalid option" do
61
+ it "returns a 404 response" do
62
+ resource = web_root.locate('invalid')
63
+
64
+ end
65
+ end
66
+ end
67
+
68
+ describe ".dispatch_specs" do
69
+ describe "#get" do
70
+ attr_reader :request, :response
71
+ before do
72
+ @request = Rack::Request.new({'rack.input' => StringIO.new("")})
73
+ @response = Rack::Response.new
74
+ end
75
+
76
+ it "redirects to /specs" do
77
+ WebRoot.dispatch_specs
78
+
79
+ web_root.get(request, response)
80
+ response.should be_redirect
81
+ response.headers["Location"].should == "/specs"
82
+ end
83
+ end
84
+
85
+ describe "#locate /specs" do
86
+ it "dispatches to a Spec::SpecDir" do
87
+ WebRoot.dispatch_specs
88
+
89
+ resource = web_root.locate('specs')
90
+ resource.should == spec_dir('')
91
+ end
92
+ end
93
+
94
+ end
95
+
96
+ describe "when .dispatch_specs is not called" do
97
+ it "does not cause #locate to dispatch to /specs" do
98
+ web_root.locate('specs').should be_instance_of(FileNotFound)
99
+ end
100
+ end
101
+ end
102
+ end
103
+ end
@@ -0,0 +1,131 @@
1
+ require File.expand_path("#{File.dirname(__FILE__)}/../unit_spec_helper")
2
+
3
+ module JsTestCore
4
+ describe Server do
5
+ attr_reader :result
6
+
7
+ before do
8
+ @result = ""
9
+ stub(EventMachine).send_data do |signature, data, data_length|
10
+ @result << data
11
+ end
12
+ stub(EventMachine).close_connection
13
+ end
14
+
15
+ describe "HTTP GET" do
16
+ specify "'/core/JsTestCore.js', returns the contents of the file" do
17
+ response = get("/core/JsTestCore.js")
18
+ response.body.should == ::File.read("#{Server.core_path}/JsTestCore.js")
19
+ end
20
+
21
+ specify "'/stylesheets/example.css', returns the contents of the file" do
22
+ response = get("/stylesheets/example.css")
23
+ response.body.should == ::File.read("#{Server.public_path}/stylesheets/example.css")
24
+ end
25
+
26
+ specify "'/invalid/path', shows the full invalid path in the error message" do
27
+ lambda do
28
+ get("/invalid/path")
29
+ end.should raise_error(Exception, Regexp.new("/invalid/path"))
30
+ end
31
+ end
32
+
33
+ describe ".run" do
34
+ attr_reader :server_instance
35
+ before do
36
+ @server_instance = Server.instance
37
+ Server.instance = nil
38
+ end
39
+
40
+ it "instantiates an instance of Server and starts a Rack Thin handler" do
41
+ host = DEFAULT_HOST
42
+ port = DEFAULT_PORT
43
+
44
+ mock(EventMachine).run.yields
45
+ mock(EventMachine).start_server(host, port, ::Thin::JsTestCoreConnection)
46
+
47
+ Server.run(spec_root_path, implementation_root_path, public_path)
48
+ end
49
+
50
+ it "when passed a custom host and port, sets the host and port to the passed in value" do
51
+ host = 'foobar.com'
52
+ port = 80
53
+
54
+ mock(EventMachine).run.yields
55
+ mock(EventMachine).start_server(host, port, ::Thin::JsTestCoreConnection)
56
+
57
+ Server.run(spec_root_path, implementation_root_path, public_path, {:Host => host, :Port => port})
58
+ end
59
+ end
60
+
61
+ describe ".spec_root" do
62
+ it "returns the Dir " do
63
+ Server.spec_root_path.should == spec_root_path
64
+ end
65
+ end
66
+
67
+ describe ".spec_root_path" do
68
+ it "returns the absolute path of the specs root directory" do
69
+ Server.spec_root_path.should == spec_root_path
70
+ end
71
+ end
72
+
73
+ describe ".public_path" do
74
+ it "returns the expanded path of the public path" do
75
+ Server.public_path.should == public_path
76
+ end
77
+ end
78
+
79
+ describe ".core_path" do
80
+ it "returns the expanded path to the JsTestCore core directory" do
81
+ Server.core_path.should == core_path
82
+ end
83
+ end
84
+
85
+ describe ".implementation_root_path" do
86
+ it "returns the expanded path to the JsTestCore implementations directory" do
87
+ dir = ::File.dirname(__FILE__)
88
+ Server.implementation_root_path.should == implementation_root_path
89
+ end
90
+ end
91
+
92
+ describe "#call" do
93
+ describe "when there is an error" do
94
+ attr_reader :top_line_of_backtrace
95
+ before do
96
+ @top_line_of_backtrace = __LINE__ + 2
97
+ stub.instance_of(Resources::WebRoot).locate('somedir') do
98
+ raise "Foobar"
99
+ end
100
+ end
101
+
102
+ it "shows the full request path in the error message" do
103
+ lambda do
104
+ get('/somedir')
105
+ end.should raise_error(Exception, Regexp.new("/somedir"))
106
+ end
107
+
108
+ it "uses the backtrace from where the original error was raised" do
109
+ no_error = true
110
+ begin
111
+ get('/somedir')
112
+ rescue Exception => e
113
+ no_error = false
114
+ top_of_backtrace = e.backtrace.first.split(":")
115
+ backtrace_file = ::File.expand_path(top_of_backtrace[0])
116
+ backtrace_line = Integer(top_of_backtrace[1])
117
+ backtrace_file.should == __FILE__
118
+ backtrace_line.should == top_line_of_backtrace
119
+ end
120
+ raise "There should have been an error" if no_error
121
+ end
122
+ end
123
+ end
124
+
125
+ describe "#root_url" do
126
+ it "returns the url of the site's root" do
127
+ server.root_url.should == "http://#{server.host}:#{server.port}"
128
+ end
129
+ end
130
+ end
131
+ end
@@ -0,0 +1,92 @@
1
+ require File.expand_path("#{File.dirname(__FILE__)}/../unit_spec_helper")
2
+
3
+ module Thin
4
+ describe JsTestCoreConnection do
5
+ describe "#process" do
6
+ attr_reader :connection, :result
7
+ before do
8
+ @connection = JsTestCoreConnection.new('signature')
9
+ stub(connection).socket_address {'0.0.0.0'}
10
+
11
+ @result = ""
12
+ stub(EventMachine).send_data do |signature, data, data_length|
13
+ result << data
14
+ end
15
+ end
16
+
17
+ describe "and the call is successful" do
18
+ describe "and the body is not empty" do
19
+ before do
20
+ mock(app = Object.new).call(is_a(Hash)) do
21
+ [200, {}, 'The Body']
22
+ end
23
+ connection.app = app
24
+ end
25
+
26
+ it "sends the response to the socket and closes the connection" do
27
+ mock(connection).close_connection_after_writing
28
+ connection.receive_data "GET /specs HTTP/1.1\r\nHost: _\r\n\r\n"
29
+ result.should include("The Body")
30
+ end
31
+ end
32
+
33
+ describe "and the body is empty" do
34
+ describe "and the Content-Length header is 0" do
35
+ before do
36
+ mock(app = Object.new).call(is_a(Hash)) do
37
+ [200, {"Content-Length" => '0'}, []]
38
+ end
39
+ connection.app = app
40
+ end
41
+
42
+ it "sends the response to the socket and closes the connection" do
43
+ mock(connection).close_connection_after_writing
44
+ connection.receive_data "GET /specs HTTP/1.1\r\nHost: _\r\n\r\n"
45
+ end
46
+ end
47
+
48
+ describe "and the Content-Length header is > 0" do
49
+ before do
50
+ mock(app = Object.new).call(is_a(Hash)) do
51
+ [200, {"Content-Length" => '55'}, []]
52
+ end
53
+ connection.app = app
54
+ end
55
+
56
+ it "keeps the connection open" do
57
+ dont_allow(connection).close_connection_after_writing
58
+ connection.receive_data "GET /specs HTTP/1.1\r\nHost: _\r\n\r\n"
59
+ end
60
+ end
61
+
62
+ describe "and the Content-Length header is not passed in" do
63
+ before do
64
+ mock(app = Object.new).call(is_a(Hash)) do
65
+ [200, {}, []]
66
+ end
67
+ connection.app = app
68
+ end
69
+
70
+ it "keeps the connection open" do
71
+ dont_allow(connection).close_connection_after_writing
72
+ connection.receive_data "GET /specs HTTP/1.1\r\nHost: _\r\n\r\n"
73
+ end
74
+ end
75
+ end
76
+ end
77
+
78
+ describe "and the call raises an error" do
79
+ it "logs the error and closes the connection" do
80
+ mock(app = Object.new).call(is_a(Hash)) do
81
+ raise "An Error"
82
+ end
83
+ connection.app = app
84
+ mock(connection).log(anything).at_least(1)
85
+ mock(connection).close_connection
86
+
87
+ connection.receive_data "GET /specs HTTP/1.1\r\nHost: _\r\n\r\n"
88
+ end
89
+ end
90
+ end
91
+ end
92
+ end