js_test_core 0.1.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (41) hide show
  1. data/CHANGES +9 -0
  2. data/README +12 -0
  3. data/Rakefile +72 -0
  4. data/lib/js_test_core.rb +30 -0
  5. data/lib/js_test_core/client.rb +50 -0
  6. data/lib/js_test_core/rack.rb +2 -0
  7. data/lib/js_test_core/rack/commonlogger.rb +5 -0
  8. data/lib/js_test_core/rails_server.rb +22 -0
  9. data/lib/js_test_core/resources.rb +10 -0
  10. data/lib/js_test_core/resources/dir.rb +52 -0
  11. data/lib/js_test_core/resources/file.rb +32 -0
  12. data/lib/js_test_core/resources/runners.rb +15 -0
  13. data/lib/js_test_core/resources/runners/firefox_runner.rb +73 -0
  14. data/lib/js_test_core/resources/specs/spec_dir.rb +50 -0
  15. data/lib/js_test_core/resources/specs/spec_file.rb +17 -0
  16. data/lib/js_test_core/resources/suite.rb +24 -0
  17. data/lib/js_test_core/resources/suite_finish.rb +19 -0
  18. data/lib/js_test_core/resources/web_root.rb +54 -0
  19. data/lib/js_test_core/selenium.rb +2 -0
  20. data/lib/js_test_core/selenium/selenium_driver.rb +5 -0
  21. data/lib/js_test_core/server.rb +111 -0
  22. data/lib/js_test_core/thin.rb +3 -0
  23. data/lib/js_test_core/thin/backends/js_test_core_server.rb +9 -0
  24. data/lib/js_test_core/thin/js_test_core_connection.rb +42 -0
  25. data/spec/spec_suite.rb +2 -0
  26. data/spec/unit/js_spec/client_spec.rb +137 -0
  27. data/spec/unit/js_spec/rails_server_spec.rb +45 -0
  28. data/spec/unit/js_spec/resources/dir_spec.rb +42 -0
  29. data/spec/unit/js_spec/resources/file_spec.rb +88 -0
  30. data/spec/unit/js_spec/resources/runner_spec.rb +24 -0
  31. data/spec/unit/js_spec/resources/runners/firefox_runner_spec.rb +161 -0
  32. data/spec/unit/js_spec/resources/specs/spec_dir_spec.rb +79 -0
  33. data/spec/unit/js_spec/resources/specs/spec_file_spec.rb +42 -0
  34. data/spec/unit/js_spec/resources/suite_finish_spec.rb +94 -0
  35. data/spec/unit/js_spec/resources/suite_spec.rb +44 -0
  36. data/spec/unit/js_spec/resources/web_root_spec.rb +67 -0
  37. data/spec/unit/js_spec/server_spec.rb +131 -0
  38. data/spec/unit/thin/js_test_core_connection_spec.rb +92 -0
  39. data/spec/unit/unit_spec_helper.rb +125 -0
  40. data/spec/unit_suite.rb +10 -0
  41. metadata +113 -0
@@ -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,67 @@
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
+ it "when passed 'core', returns a Dir representing the JsTestCore core directory" do
13
+ runner = web_root.locate('core')
14
+ runner.should == Resources::Dir.new(JsTestCore::Server.core_path, '/core')
15
+ end
16
+
17
+ it "when passed 'implementations', returns a Dir representing the javascript implementations directory" do
18
+ runner = web_root.locate('implementations')
19
+ runner.should == Resources::Dir.new(JsTestCore::Server.implementation_root_path, '/implementations')
20
+ end
21
+
22
+ it "when passed 'results', returns a Suite" do
23
+ runner = web_root.locate('suites')
24
+ runner.should == Resources::Suite
25
+ end
26
+
27
+ it "when passed 'runners', returns a Runner" do
28
+ runner = web_root.locate('runners')
29
+ runner.should be_instance_of(Resources::Runners)
30
+ end
31
+
32
+ it "when passed a directory that is in the public_path, returns a Dir representing that directory" do
33
+ runner = web_root.locate('stylesheets')
34
+ runner.should == Resources::Dir.new("#{JsTestCore::Server.public_path}/stylesheets", '/stylesheets')
35
+ end
36
+
37
+ it "when passed a file that is in the public_path, returns a File representing that file" do
38
+ runner = web_root.locate('robots.txt')
39
+ runner.should == Resources::File.new("#{JsTestCore::Server.public_path}/robots.txt", '/robots.txt')
40
+ end
41
+
42
+ it "when not passed 'core' or 'specs', raises an error" do
43
+ lambda do
44
+ web_root.locate('invalid')
45
+ end.should raise_error
46
+ end
47
+ end
48
+
49
+ describe ".dispatch_specs" do
50
+ it "causes #locate /specs to dispatch to a Spec::SpecDir" do
51
+ WebRoot.dispatch_specs
52
+
53
+ resource = web_root.locate('specs')
54
+ resource.should == spec_dir('')
55
+ end
56
+ end
57
+
58
+ describe "when .dispatch_specs is not called" do
59
+ it "does not cause #locate to dispatch to /specs" do
60
+ lambda do
61
+ web_root.locate('specs')
62
+ end.should raise_error
63
+ end
64
+ end
65
+ end
66
+ end
67
+ 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
@@ -0,0 +1,125 @@
1
+ require "rubygems"
2
+ require "spec"
3
+
4
+ dir = File.dirname(__FILE__)
5
+ $LOAD_PATH.unshift "#{dir}/../../lib"
6
+ require "js_test_core"
7
+ require "hpricot"
8
+ require "guid"
9
+
10
+ Spec::Runner.configure do |config|
11
+ config.mock_with :rr
12
+ end
13
+
14
+ module Spec
15
+ module Matchers
16
+ class Exist
17
+ def matches?(actual)
18
+ @actual = actual
19
+ !@actual.nil?
20
+ end
21
+ end
22
+ end
23
+ end
24
+
25
+ class Spec::Example::ExampleGroup
26
+ class << self
27
+ def thin_logging
28
+ @thin_logging = true if @thin_logging.nil?
29
+ @thin_logging
30
+ end
31
+
32
+ attr_writer :thin_logging
33
+ end
34
+ end
35
+
36
+ class JsTestCoreTestDir < JsTestCore::Resources::Dir
37
+ def get(request, response)
38
+
39
+ end
40
+ end
41
+
42
+ module Spec::Example::ExampleMethods
43
+ attr_reader :core_path, :spec_root_path, :implementation_root_path, :public_path, :server, :connection
44
+ before(:all) do
45
+ dir = File.dirname(__FILE__)
46
+ @core_path = File.expand_path("#{dir}/../example_core")
47
+ JsTestCore.core_path = core_path
48
+ @spec_root_path = File.expand_path("#{dir}/../example_specs")
49
+ @implementation_root_path = File.expand_path("#{dir}/../example_public/javascripts")
50
+ @public_path = File.expand_path("#{dir}/../example_public")
51
+ end
52
+
53
+ before(:each) do
54
+ JsTestCore::Server.instance = JsTestCore::Server.new(spec_root_path, implementation_root_path, public_path)
55
+ stub(EventMachine).run do
56
+ raise "You need to mock calls to EventMachine.run or the process will hang"
57
+ end
58
+ stub(EventMachine).start_server do
59
+ raise "You need to mock calls to EventMachine.start_server or the process will hang"
60
+ end
61
+ stub(EventMachine).send_data do
62
+ raise "Calls to EventMachine.send_data must be mocked or stubbed"
63
+ end
64
+ @connection = Thin::JsTestCoreConnection.new(Guid.new)
65
+ stub(EventMachine).send_data {raise "EventMachine.send_data must be handled"}
66
+ stub(EventMachine).close_connection {raise "EventMachine.close_connection must be handled"}
67
+ @server = JsTestCore::Server.instance
68
+ Thin::Logging.silent = !self.class.thin_logging
69
+ Thin::Logging.debug = self.class.thin_logging
70
+ end
71
+
72
+ after(:each) do
73
+ JsTestCore::Resources::WebRoot.dispatch_strategy = nil
74
+ Thin::Logging.silent = true
75
+ Thin::Logging.debug = false
76
+ end
77
+
78
+ def get(url, params={})
79
+ request(:get, url, params)
80
+ end
81
+
82
+ def post(url, params={})
83
+ request(:post, url, params)
84
+ end
85
+
86
+ def put(url, params={})
87
+ request(:put, url, params)
88
+ end
89
+
90
+ def delete(url, params={})
91
+ request(:delete, url, params)
92
+ end
93
+
94
+ def env_for(method, url, params)
95
+ Rack::MockRequest.env_for(url, params.merge({:method => method.to_s.upcase, 'js_test_core.connection' => connection}))
96
+ end
97
+
98
+ def create_request(method, url, params={})
99
+ env = env_for(method, url, params)
100
+ server.call(env)[2]
101
+ end
102
+ alias_method :request, :create_request
103
+
104
+ def spec_file(relative_path)
105
+ absolute_path = spec_root_path + relative_path
106
+ JsTestCore::Resources::File.new(absolute_path, "/specs#{relative_path}")
107
+ end
108
+
109
+ def spec_dir(relative_path="")
110
+ absolute_path = spec_root_path + relative_path
111
+ JsTestCore::Resources::Specs::SpecDir.new(absolute_path, "/specs#{relative_path}")
112
+ end
113
+
114
+ def contain_spec_file_with_correct_paths(path_relative_to_spec_root)
115
+ expected_absolute_path = spec_root_path + path_relative_to_spec_root
116
+ expected_relative_path = "/specs" + path_relative_to_spec_root
117
+
118
+ ::Spec::Matchers::SimpleMatcher.new(expected_relative_path) do |globbed_files|
119
+ file = globbed_files.find do |file|
120
+ file.absolute_path == expected_absolute_path
121
+ end
122
+ file && file.relative_path == expected_relative_path
123
+ end
124
+ end
125
+ end