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