js_test_core 0.1.1
Sign up to get free protection for your applications and to get access to all the features.
- 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,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,54 @@
|
|
1
|
+
module JsTestCore
|
2
|
+
module Resources
|
3
|
+
class WebRoot
|
4
|
+
LOCATIONS = [
|
5
|
+
['core', lambda do
|
6
|
+
Resources::Dir.new(JsTestCore::Server.core_path, "/core")
|
7
|
+
end],
|
8
|
+
['implementations', lambda do
|
9
|
+
Resources::Dir.new(JsTestCore::Server.implementation_root_path, "/implementations")
|
10
|
+
end],
|
11
|
+
['suites', lambda do
|
12
|
+
Resources::Suite
|
13
|
+
end],
|
14
|
+
['runners', lambda do
|
15
|
+
Resources::Runners.new
|
16
|
+
end]
|
17
|
+
]
|
18
|
+
|
19
|
+
class << self
|
20
|
+
attr_accessor :dispatch_strategy
|
21
|
+
def dispatch_specs
|
22
|
+
self.dispatch_strategy = :specs
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
attr_reader :public_path
|
27
|
+
def initialize(public_path)
|
28
|
+
@public_path = ::File.expand_path(public_path)
|
29
|
+
end
|
30
|
+
|
31
|
+
def locate(name)
|
32
|
+
if self.class.dispatch_strategy == :specs && name == 'specs'
|
33
|
+
return JsTestCore::Resources::Specs::SpecDir.new(JsTestCore::Server.spec_root_path, "/specs")
|
34
|
+
end
|
35
|
+
|
36
|
+
location, initializer = LOCATIONS.find do |location|
|
37
|
+
location.first == name
|
38
|
+
end
|
39
|
+
if initializer
|
40
|
+
initializer.call
|
41
|
+
else
|
42
|
+
potential_file_in_public_path = "#{public_path}/#{name}"
|
43
|
+
if ::File.directory?(potential_file_in_public_path)
|
44
|
+
Resources::Dir.new(potential_file_in_public_path, "/#{name}")
|
45
|
+
elsif ::File.exists?(potential_file_in_public_path)
|
46
|
+
Resources::File.new(potential_file_in_public_path, "/#{name}")
|
47
|
+
else
|
48
|
+
raise "Invalid path: #{name}"
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
@@ -0,0 +1,111 @@
|
|
1
|
+
module JsTestCore
|
2
|
+
class Server
|
3
|
+
class << self
|
4
|
+
attr_accessor :instance
|
5
|
+
|
6
|
+
def run(spec_root_path, implementation_root_path, public_path, server_options = {})
|
7
|
+
server_options[:Host] ||= DEFAULT_HOST
|
8
|
+
server_options[:Port] ||= DEFAULT_PORT
|
9
|
+
@instance = new(spec_root_path, implementation_root_path, public_path, server_options[:Host], server_options[:Port])
|
10
|
+
instance.run server_options
|
11
|
+
end
|
12
|
+
|
13
|
+
def spec_root_path; instance.spec_root_path; end
|
14
|
+
def implementation_root_path; instance.implementation_root_path; end
|
15
|
+
def public_path; instance.public_path; end
|
16
|
+
def core_path; instance.core_path; end
|
17
|
+
def test_dir_class; instance.test_dir_class; end
|
18
|
+
def test_file_class; instance.test_file_class; end
|
19
|
+
def connection; instance.connection; end
|
20
|
+
def request; instance.request; end
|
21
|
+
def response; instance.response; end
|
22
|
+
def root_url; instance.root_url; end
|
23
|
+
end
|
24
|
+
|
25
|
+
attr_reader :host, :port, :spec_root_path, :implementation_root_path, :public_path
|
26
|
+
|
27
|
+
def initialize(spec_root_path, implementation_root_path, public_path, host=DEFAULT_HOST, port=DEFAULT_PORT)
|
28
|
+
dir = ::File.dirname(__FILE__)
|
29
|
+
@spec_root_path = ::File.expand_path(spec_root_path)
|
30
|
+
@implementation_root_path = ::File.expand_path(implementation_root_path)
|
31
|
+
@public_path = ::File.expand_path(public_path)
|
32
|
+
@host = host
|
33
|
+
@port = port
|
34
|
+
end
|
35
|
+
|
36
|
+
def run(options)
|
37
|
+
server = ::Thin::Server.new(options[:Host], options[:Port], self)
|
38
|
+
server.backend = ::Thin::Backends::JsTestCoreServer.new(options[:Host], options[:Port])
|
39
|
+
server.backend.server = server
|
40
|
+
server.start!
|
41
|
+
end
|
42
|
+
|
43
|
+
def call(env)
|
44
|
+
self.connection = env['js_test_core.connection']
|
45
|
+
self.request = Rack::Request.new(env)
|
46
|
+
self.response = Rack::Response.new
|
47
|
+
method = request.request_method.downcase.to_sym
|
48
|
+
get_resource(request).send(method, request, response)
|
49
|
+
response.finish
|
50
|
+
ensure
|
51
|
+
self.connection = nil
|
52
|
+
self.request = nil
|
53
|
+
self.response = nil
|
54
|
+
end
|
55
|
+
|
56
|
+
def connection
|
57
|
+
Thread.current[:connection]
|
58
|
+
end
|
59
|
+
|
60
|
+
def request
|
61
|
+
Thread.current[:request]
|
62
|
+
end
|
63
|
+
|
64
|
+
def response
|
65
|
+
Thread.current[:response]
|
66
|
+
end
|
67
|
+
|
68
|
+
def root_url
|
69
|
+
"http://#{host}:#{port}"
|
70
|
+
end
|
71
|
+
|
72
|
+
def core_path
|
73
|
+
JsTestCore.core_path
|
74
|
+
end
|
75
|
+
|
76
|
+
def test_dir_class
|
77
|
+
JsTestCore.adapter.test_dir_class
|
78
|
+
end
|
79
|
+
|
80
|
+
def test_file_class
|
81
|
+
JsTestCore.adapter.test_file_class
|
82
|
+
end
|
83
|
+
|
84
|
+
protected
|
85
|
+
def connection=(connection)
|
86
|
+
Thread.current[:connection] = connection
|
87
|
+
end
|
88
|
+
|
89
|
+
def request=(request)
|
90
|
+
Thread.current[:request] = request
|
91
|
+
end
|
92
|
+
|
93
|
+
def response=(response)
|
94
|
+
Thread.current[:response] = response
|
95
|
+
end
|
96
|
+
|
97
|
+
def path_parts(req)
|
98
|
+
request.path_info.split('/').reject { |part| part == "" }
|
99
|
+
end
|
100
|
+
|
101
|
+
def get_resource(request)
|
102
|
+
path_parts(request).inject(Resources::WebRoot.new(public_path)) do |resource, child_resource_name|
|
103
|
+
resource.locate(child_resource_name)
|
104
|
+
end
|
105
|
+
rescue Exception => e
|
106
|
+
detailed_exception = Exception.new("Error handling path #{request.path_info}\n#{e.message}")
|
107
|
+
detailed_exception.set_backtrace(e.backtrace)
|
108
|
+
raise detailed_exception
|
109
|
+
end
|
110
|
+
end
|
111
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
module Thin
|
2
|
+
class JsTestCoreConnection < Connection
|
3
|
+
def process
|
4
|
+
# Add client info to the request env
|
5
|
+
@request.remote_address = remote_address
|
6
|
+
|
7
|
+
env = @request.env
|
8
|
+
env['js_test_core.connection'] = self
|
9
|
+
@response.status, @response.headers, @response.body = @app.call(env)
|
10
|
+
send_data @response.head
|
11
|
+
if !@response.body.empty? || @response.headers.to_s.include?("Content-Length: 0")
|
12
|
+
send_body @response.body
|
13
|
+
end
|
14
|
+
rescue Exception => e
|
15
|
+
handle_error e
|
16
|
+
end
|
17
|
+
|
18
|
+
def send_body(rack_response)
|
19
|
+
rack_response.each do |chunk|
|
20
|
+
send_data chunk
|
21
|
+
end
|
22
|
+
# If no more request on that same connection, we close it.
|
23
|
+
close_connection_after_writing unless persistent?
|
24
|
+
rescue Exception => e
|
25
|
+
handle_error e
|
26
|
+
ensure
|
27
|
+
@request.close rescue nil
|
28
|
+
@response.close rescue nil
|
29
|
+
|
30
|
+
# Prepare the connection for another request if the client
|
31
|
+
# supports HTTP pipelining (persistent connection).
|
32
|
+
post_init if persistent?
|
33
|
+
end
|
34
|
+
|
35
|
+
def handle_error(error)
|
36
|
+
log "!! Unexpected error while processing request: #{error.message}"
|
37
|
+
log error.backtrace
|
38
|
+
log_error
|
39
|
+
close_connection rescue nil
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
data/spec/spec_suite.rb
ADDED
@@ -0,0 +1,137 @@
|
|
1
|
+
require File.expand_path("#{File.dirname(__FILE__)}/../unit_spec_helper")
|
2
|
+
|
3
|
+
module JsTestCore
|
4
|
+
describe Client do
|
5
|
+
describe '.run' do
|
6
|
+
describe 'when successful' do
|
7
|
+
before do
|
8
|
+
request = Object.new
|
9
|
+
mock(request).post("/runners/firefox", "selenium_host=localhost&selenium_port=4444")
|
10
|
+
response = Object.new
|
11
|
+
mock(response).body {""}
|
12
|
+
mock(Net::HTTP).start(DEFAULT_HOST, DEFAULT_PORT).yields(request) {response}
|
13
|
+
stub(Client).puts
|
14
|
+
end
|
15
|
+
|
16
|
+
it "returns true" do
|
17
|
+
Client.run.should be_true
|
18
|
+
end
|
19
|
+
|
20
|
+
it "prints 'SUCCESS'" do
|
21
|
+
mock(Client).puts("SUCCESS")
|
22
|
+
Client.run
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
describe 'when unsuccessful' do
|
27
|
+
before do
|
28
|
+
request = Object.new
|
29
|
+
mock(request).post("/runners/firefox", "selenium_host=localhost&selenium_port=4444")
|
30
|
+
response = Object.new
|
31
|
+
mock(response).body {"the failure message"}
|
32
|
+
mock(Net::HTTP).start(DEFAULT_HOST, DEFAULT_PORT).yields(request) {response}
|
33
|
+
stub(Client).puts
|
34
|
+
end
|
35
|
+
|
36
|
+
it "returns false" do
|
37
|
+
Client.run.should be_false
|
38
|
+
end
|
39
|
+
|
40
|
+
it "prints 'FAILURE' and the error message(s)" do
|
41
|
+
mock(Client).puts("FAILURE")
|
42
|
+
mock(Client).puts("the failure message")
|
43
|
+
Client.run
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
describe "arguments" do
|
48
|
+
attr_reader :request, :response
|
49
|
+
before do
|
50
|
+
@request = Object.new
|
51
|
+
@response = Object.new
|
52
|
+
mock(response).body {""}
|
53
|
+
mock(Net::HTTP).start(DEFAULT_HOST, DEFAULT_PORT).yields(request) {response}
|
54
|
+
stub(Client).puts
|
55
|
+
end
|
56
|
+
|
57
|
+
describe "when passed a custom spec_url" do
|
58
|
+
it "passes the spec_url as a post parameter" do
|
59
|
+
spec_url = 'http://foobar.com/foo'
|
60
|
+
mock(request).post(
|
61
|
+
"/runners/firefox",
|
62
|
+
"selenium_host=localhost&selenium_port=4444&spec_url=#{CGI.escape(spec_url)}"
|
63
|
+
)
|
64
|
+
Client.run(:spec_url => spec_url)
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
describe "when passed a custom selenium host" do
|
69
|
+
it "passes the selenium_host as a post parameter" do
|
70
|
+
selenium_host = 'test-runner'
|
71
|
+
mock(request).post(
|
72
|
+
"/runners/firefox",
|
73
|
+
"selenium_host=test-runner&selenium_port=4444"
|
74
|
+
)
|
75
|
+
Client.run(:selenium_host => selenium_host)
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
describe "when passed a custom selenium port" do
|
80
|
+
it "passes the selenium_port as a post parameter" do
|
81
|
+
selenium_port = 5000
|
82
|
+
mock(request).post(
|
83
|
+
"/runners/firefox",
|
84
|
+
"selenium_host=localhost&selenium_port=5000"
|
85
|
+
)
|
86
|
+
Client.run(:selenium_port => selenium_port)
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
end
|
92
|
+
|
93
|
+
describe ".run_argv" do
|
94
|
+
attr_reader :request, :response
|
95
|
+
before do
|
96
|
+
@request = Object.new
|
97
|
+
@response = Object.new
|
98
|
+
mock(response).body {""}
|
99
|
+
mock(Net::HTTP).start(DEFAULT_HOST, DEFAULT_PORT).yields(request) {response}
|
100
|
+
stub(Client).puts
|
101
|
+
end
|
102
|
+
|
103
|
+
describe "when passed a custom spec_url" do
|
104
|
+
it "passes the spec_url as a post parameter" do
|
105
|
+
spec_url = 'http://foobar.com/foo'
|
106
|
+
mock(request).post(
|
107
|
+
"/runners/firefox",
|
108
|
+
"selenium_host=localhost&selenium_port=4444&spec_url=#{CGI.escape(spec_url)}"
|
109
|
+
)
|
110
|
+
Client.run_argv(['--spec_url', spec_url])
|
111
|
+
end
|
112
|
+
end
|
113
|
+
|
114
|
+
describe "when passed a custom selenium host" do
|
115
|
+
it "passes the selenium_host as a post parameter" do
|
116
|
+
selenium_host = 'test-runner'
|
117
|
+
mock(request).post(
|
118
|
+
"/runners/firefox",
|
119
|
+
"selenium_host=test-runner&selenium_port=4444"
|
120
|
+
)
|
121
|
+
Client.run_argv(['--selenium_host', selenium_host])
|
122
|
+
end
|
123
|
+
end
|
124
|
+
|
125
|
+
describe "when passed a custom selenium port" do
|
126
|
+
it "passes the selenium_port as a post parameter" do
|
127
|
+
selenium_port = 5000
|
128
|
+
mock(request).post(
|
129
|
+
"/runners/firefox",
|
130
|
+
"selenium_host=localhost&selenium_port=5000"
|
131
|
+
)
|
132
|
+
Client.run_argv(['--selenium_port', selenium_port.to_s])
|
133
|
+
end
|
134
|
+
end
|
135
|
+
end
|
136
|
+
end
|
137
|
+
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
require File.expand_path("#{File.dirname(__FILE__)}/../unit_spec_helper")
|
2
|
+
|
3
|
+
module JsTestCore
|
4
|
+
describe RailsServer do
|
5
|
+
it "subclasses Server" do
|
6
|
+
RailsServer.superclass.should == Server
|
7
|
+
end
|
8
|
+
|
9
|
+
describe ".run" do
|
10
|
+
attr_reader :rails_root
|
11
|
+
before do
|
12
|
+
@rails_root = "/rails/root"
|
13
|
+
Server.instance = nil
|
14
|
+
end
|
15
|
+
|
16
|
+
it "initializes the RailsServer and runs the Thin Handler and sets Server.instance to the RailsServer instance" do
|
17
|
+
host = DEFAULT_HOST
|
18
|
+
port = DEFAULT_PORT
|
19
|
+
server_instance = nil
|
20
|
+
mock.proxy(RailsServer).new(
|
21
|
+
rails_root,
|
22
|
+
host,
|
23
|
+
port
|
24
|
+
) do |new_instance|
|
25
|
+
server_instance = new_instance
|
26
|
+
end
|
27
|
+
|
28
|
+
mock(EventMachine).run.yields
|
29
|
+
mock(EventMachine).start_server(host, port, ::Thin::JsTestCoreConnection)
|
30
|
+
RailsServer.run(rails_root)
|
31
|
+
Server.instance.should == server_instance
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
describe "#initialize" do
|
36
|
+
it "sets the server paths based on the passed in rails root" do
|
37
|
+
rails_root = "/rails/root"
|
38
|
+
server = RailsServer.new(rails_root)
|
39
|
+
server.spec_root_path.should == "#{rails_root}/spec/javascripts"
|
40
|
+
server.implementation_root_path.should == "#{rails_root}/public/javascripts"
|
41
|
+
server.public_path.should == "#{rails_root}/public"
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|