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.
- data/CHANGES +9 -0
- data/README +12 -0
- data/Rakefile +72 -0
- data/lib/js_test_core.rb +30 -0
- data/lib/js_test_core/client.rb +50 -0
- data/lib/js_test_core/rack.rb +2 -0
- data/lib/js_test_core/rack/commonlogger.rb +5 -0
- data/lib/js_test_core/rails_server.rb +22 -0
- data/lib/js_test_core/resources.rb +10 -0
- data/lib/js_test_core/resources/dir.rb +52 -0
- data/lib/js_test_core/resources/file.rb +32 -0
- data/lib/js_test_core/resources/runners.rb +15 -0
- data/lib/js_test_core/resources/runners/firefox_runner.rb +73 -0
- data/lib/js_test_core/resources/specs/spec_dir.rb +50 -0
- data/lib/js_test_core/resources/specs/spec_file.rb +17 -0
- data/lib/js_test_core/resources/suite.rb +24 -0
- data/lib/js_test_core/resources/suite_finish.rb +19 -0
- data/lib/js_test_core/resources/web_root.rb +54 -0
- data/lib/js_test_core/selenium.rb +2 -0
- data/lib/js_test_core/selenium/selenium_driver.rb +5 -0
- data/lib/js_test_core/server.rb +111 -0
- data/lib/js_test_core/thin.rb +3 -0
- data/lib/js_test_core/thin/backends/js_test_core_server.rb +9 -0
- data/lib/js_test_core/thin/js_test_core_connection.rb +42 -0
- data/spec/spec_suite.rb +2 -0
- data/spec/unit/js_spec/client_spec.rb +137 -0
- data/spec/unit/js_spec/rails_server_spec.rb +45 -0
- data/spec/unit/js_spec/resources/dir_spec.rb +42 -0
- data/spec/unit/js_spec/resources/file_spec.rb +88 -0
- data/spec/unit/js_spec/resources/runner_spec.rb +24 -0
- data/spec/unit/js_spec/resources/runners/firefox_runner_spec.rb +161 -0
- data/spec/unit/js_spec/resources/specs/spec_dir_spec.rb +79 -0
- data/spec/unit/js_spec/resources/specs/spec_file_spec.rb +42 -0
- data/spec/unit/js_spec/resources/suite_finish_spec.rb +94 -0
- data/spec/unit/js_spec/resources/suite_spec.rb +44 -0
- data/spec/unit/js_spec/resources/web_root_spec.rb +67 -0
- data/spec/unit/js_spec/server_spec.rb +131 -0
- data/spec/unit/thin/js_test_core_connection_spec.rb +92 -0
- data/spec/unit/unit_spec_helper.rb +125 -0
- data/spec/unit_suite.rb +10 -0
- 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
|