js_test_core 0.1.1

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 (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