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
data/CHANGES
ADDED
@@ -0,0 +1,9 @@
|
|
1
|
+
0.1.1
|
2
|
+
- SuiteFinish#post immediately closes the connection
|
3
|
+
|
4
|
+
0.1.0
|
5
|
+
- Initial Release extracted from JsTestCore.
|
6
|
+
- Added JsTestCore::WebRoot.dispatch_specs and .dispatch_strategy
|
7
|
+
- Extracted JsTestCore::Resources::Specs::SpecDir
|
8
|
+
- Extracted JsTestCore::Resources::Specs::SpecFile
|
9
|
+
- No longer depending on Guid. The child libraries are responsible for obtaining the Selenium session_id from the client by using top.runOptions.getSessionId().
|
data/README
ADDED
@@ -0,0 +1,12 @@
|
|
1
|
+
= JsTestCore
|
2
|
+
The JsTestCore library is the core javascript test server library used by several JS Test server libraries.
|
3
|
+
|
4
|
+
To hook up your own JS Test framework:
|
5
|
+
* You will need to call either JsTestCore::Resources::WebRoot.dispatch_specs or JsTestCore::Resources::WebRoot.dispatch_tests
|
6
|
+
depending if you are serving specs or tests.
|
7
|
+
* Set JsTestCore.core_path to the directory of the client side test framework (javascript files)
|
8
|
+
* Override JsTestCore::Resources::Specs::SpecFile#get or JsTestCore::Resources::Specs::TestFile#get
|
9
|
+
* Override JsTestCore::Resources::Specs::SpecDir#get or JsTestCore::Resources::Specs::TestDir#get
|
10
|
+
|
11
|
+
NOTE: The current version of JsTestCore does not yet support tests. Support will be added soon.
|
12
|
+
I just wanted the test stuff to be in the docs to establish the current architectural direction.
|
data/Rakefile
ADDED
@@ -0,0 +1,72 @@
|
|
1
|
+
require "rake"
|
2
|
+
require 'rake/gempackagetask'
|
3
|
+
require 'rake/contrib/rubyforgepublisher'
|
4
|
+
require 'rake/clean'
|
5
|
+
require 'rake/testtask'
|
6
|
+
require 'rake/rdoctask'
|
7
|
+
|
8
|
+
desc "Runs the Rspec suite"
|
9
|
+
task(:default) do
|
10
|
+
run_suite
|
11
|
+
end
|
12
|
+
|
13
|
+
desc "Runs the Rspec suite"
|
14
|
+
task(:spec) do
|
15
|
+
run_suite
|
16
|
+
end
|
17
|
+
|
18
|
+
desc "Copies the trunk to a tag with the name of the current release"
|
19
|
+
task(:tag_release) do
|
20
|
+
tag_release
|
21
|
+
end
|
22
|
+
|
23
|
+
def run_suite
|
24
|
+
dir = File.dirname(__FILE__)
|
25
|
+
system("ruby #{dir}/spec/spec_suite.rb") || raise("Example Suite failed")
|
26
|
+
end
|
27
|
+
|
28
|
+
PKG_NAME = "js_test_core"
|
29
|
+
PKG_VERSION = "0.1.1"
|
30
|
+
PKG_FILES = FileList[
|
31
|
+
'[A-Z]*',
|
32
|
+
'*.rb',
|
33
|
+
'lib/**/*.rb',
|
34
|
+
'core/**',
|
35
|
+
'bin/**',
|
36
|
+
'spec/**/*.rb'
|
37
|
+
]
|
38
|
+
|
39
|
+
spec = Gem::Specification.new do |s|
|
40
|
+
s.name = PKG_NAME
|
41
|
+
s.version = PKG_VERSION
|
42
|
+
s.summary = "The JsTestCore library is the core javascript test server library used by several JS Test server libraries."
|
43
|
+
s.test_files = "spec/spec_suite.rb"
|
44
|
+
s.description = s.summary
|
45
|
+
|
46
|
+
s.files = PKG_FILES.to_a
|
47
|
+
s.require_path = 'lib'
|
48
|
+
|
49
|
+
s.has_rdoc = true
|
50
|
+
s.extra_rdoc_files = [ "README", "CHANGES" ]
|
51
|
+
s.rdoc_options = ["--main", "README", "--inline-source", "--line-numbers"]
|
52
|
+
|
53
|
+
s.test_files = Dir.glob('spec/*_spec.rb')
|
54
|
+
s.require_path = 'lib'
|
55
|
+
s.author = "Brian Takita"
|
56
|
+
s.email = "brian@pivotallabs.com"
|
57
|
+
s.homepage = "http://pivotallabs.com"
|
58
|
+
s.rubyforge_project = "pivotalrb"
|
59
|
+
s.add_dependency('Selenium')
|
60
|
+
s.add_dependency('thin', '=0.8.1')
|
61
|
+
end
|
62
|
+
|
63
|
+
Rake::GemPackageTask.new(spec) do |pkg|
|
64
|
+
pkg.need_zip = true
|
65
|
+
pkg.need_tar = true
|
66
|
+
end
|
67
|
+
|
68
|
+
def tag_release
|
69
|
+
dashed_version = PKG_VERSION.gsub('.', '-')
|
70
|
+
svn_user = "#{ENV["SVN_USER"]}@" || ""
|
71
|
+
`svn cp svn+ssh://#{svn_user}rubyforge.org/var/svn/pivotalrb/js_test_core/trunk svn+ssh://#{svn_user}rubyforge.org/var/svn/pivotalrb/js_test_core/tags/REL-#{dashed_version} -m 'Version #{PKG_VERSION}'`
|
72
|
+
end
|
data/lib/js_test_core.rb
ADDED
@@ -0,0 +1,30 @@
|
|
1
|
+
require "rubygems"
|
2
|
+
gem "thin", ">=0.8.0"
|
3
|
+
|
4
|
+
require "thin"
|
5
|
+
require "fileutils"
|
6
|
+
require "tmpdir"
|
7
|
+
require "timeout"
|
8
|
+
require "cgi"
|
9
|
+
require "net/http"
|
10
|
+
require "selenium"
|
11
|
+
require "optparse"
|
12
|
+
|
13
|
+
dir = File.dirname(__FILE__)
|
14
|
+
require "#{dir}/js_test_core/thin"
|
15
|
+
require "#{dir}/js_test_core/rack"
|
16
|
+
require "#{dir}/js_test_core/resources"
|
17
|
+
require "#{dir}/js_test_core/selenium"
|
18
|
+
|
19
|
+
require "#{dir}/js_test_core/client"
|
20
|
+
require "#{dir}/js_test_core/server"
|
21
|
+
require "#{dir}/js_test_core/rails_server"
|
22
|
+
|
23
|
+
module JsTestCore
|
24
|
+
DEFAULT_HOST = "0.0.0.0"
|
25
|
+
DEFAULT_PORT = 8080
|
26
|
+
|
27
|
+
class << self
|
28
|
+
attr_accessor :core_path
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,50 @@
|
|
1
|
+
module JsTestCore
|
2
|
+
class Client
|
3
|
+
class << self
|
4
|
+
def run(params={})
|
5
|
+
data = []
|
6
|
+
data << "selenium_host=#{CGI.escape(params[:selenium_host] || 'localhost')}"
|
7
|
+
data << "selenium_port=#{CGI.escape((params[:selenium_port] || 4444).to_s)}"
|
8
|
+
data << "spec_url=#{CGI.escape(params[:spec_url])}" if params[:spec_url]
|
9
|
+
response = Net::HTTP.start(DEFAULT_HOST, DEFAULT_PORT) do |http|
|
10
|
+
http.post('/runners/firefox', data.join("&"))
|
11
|
+
end
|
12
|
+
|
13
|
+
body = response.body
|
14
|
+
if body.empty?
|
15
|
+
puts "SUCCESS"
|
16
|
+
return true
|
17
|
+
else
|
18
|
+
puts "FAILURE"
|
19
|
+
puts body
|
20
|
+
return false
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
def run_argv(argv)
|
25
|
+
params = {}
|
26
|
+
parser = OptionParser.new do |o|
|
27
|
+
o.banner = "JsTestCore Runner"
|
28
|
+
o.banner << "\nUsage: #{$0} [options] [-- untouched arguments]"
|
29
|
+
|
30
|
+
o.on
|
31
|
+
o.on('-h', '--selenium_host=SELENIUM_HOST', "The host name of the Selenium Server relative to where this file is executed") do |host|
|
32
|
+
params[:selenium_host] = host
|
33
|
+
end
|
34
|
+
|
35
|
+
o.on('-p', '--selenium_port=SELENIUM_PORT', "The port of the Selenium Server relative to where this file is executed") do |port|
|
36
|
+
params[:selenium_port] = port
|
37
|
+
end
|
38
|
+
|
39
|
+
o.on('-u', '--spec_url=SPEC_URL', "The url of the js spec server, relative to the browsers running via the Selenium Server") do |spec_url|
|
40
|
+
params[:spec_url] = spec_url
|
41
|
+
end
|
42
|
+
|
43
|
+
o.on_tail
|
44
|
+
end
|
45
|
+
parser.order!(argv)
|
46
|
+
run params
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
module JsTestCore
|
2
|
+
class RailsServer < Server
|
3
|
+
class << self
|
4
|
+
def run(rails_root, server_options = {})
|
5
|
+
server_options[:Host] ||= DEFAULT_HOST
|
6
|
+
server_options[:Port] ||= DEFAULT_PORT
|
7
|
+
Server.instance = new(rails_root, server_options[:Host], server_options[:Port])
|
8
|
+
Server.instance.run server_options
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
def initialize(rails_root, host=DEFAULT_HOST, port=DEFAULT_PORT)
|
13
|
+
super(
|
14
|
+
"#{rails_root}/spec/javascripts",
|
15
|
+
"#{rails_root}/public/javascripts",
|
16
|
+
"#{rails_root}/public",
|
17
|
+
host,
|
18
|
+
port
|
19
|
+
)
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,10 @@
|
|
1
|
+
dir = File.dirname(__FILE__)
|
2
|
+
require "#{dir}/resources/runners"
|
3
|
+
require "#{dir}/resources/runners/firefox_runner"
|
4
|
+
require "#{dir}/resources/file"
|
5
|
+
require "#{dir}/resources/dir"
|
6
|
+
require "#{dir}/resources/specs/spec_file"
|
7
|
+
require "#{dir}/resources/specs/spec_dir"
|
8
|
+
require "#{dir}/resources/web_root"
|
9
|
+
require "#{dir}/resources/suite"
|
10
|
+
require "#{dir}/resources/suite_finish"
|
@@ -0,0 +1,52 @@
|
|
1
|
+
module JsTestCore
|
2
|
+
module Resources
|
3
|
+
class Dir < File
|
4
|
+
def locate(name)
|
5
|
+
if file = file(name)
|
6
|
+
file
|
7
|
+
elsif subdir = subdir(name)
|
8
|
+
subdir
|
9
|
+
else
|
10
|
+
raise "No file or directory found at #{relative_path}/#{name}."
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
def get(request, response)
|
15
|
+
|
16
|
+
end
|
17
|
+
|
18
|
+
def glob(pattern)
|
19
|
+
expanded_pattern = absolute_path + pattern
|
20
|
+
::Dir.glob(expanded_pattern).map do |absolute_globbed_path|
|
21
|
+
relative_globbed_path = absolute_globbed_path.gsub(absolute_path, relative_path)
|
22
|
+
File.new(absolute_globbed_path, relative_globbed_path)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
protected
|
27
|
+
def determine_child_paths(name)
|
28
|
+
absolute_child_path = "#{absolute_path}/#{name}"
|
29
|
+
relative_child_path = "#{relative_path}/#{name}"
|
30
|
+
[absolute_child_path, relative_child_path]
|
31
|
+
end
|
32
|
+
|
33
|
+
def file(name)
|
34
|
+
absolute_file_path, relative_file_path = determine_child_paths(name)
|
35
|
+
if ::File.exists?(absolute_file_path) && !::File.directory?(absolute_file_path)
|
36
|
+
Resources::File.new(absolute_file_path, relative_file_path)
|
37
|
+
else
|
38
|
+
nil
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
def subdir(name)
|
43
|
+
absolute_dir_path, relative_dir_path = determine_child_paths(name)
|
44
|
+
if ::File.directory?(absolute_dir_path)
|
45
|
+
Resources::Dir.new(absolute_dir_path, relative_dir_path)
|
46
|
+
else
|
47
|
+
nil
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
module JsTestCore
|
2
|
+
module Resources
|
3
|
+
class File
|
4
|
+
MIME_TYPES = {
|
5
|
+
'.js' => 'text/javascript',
|
6
|
+
'.css' => 'text/css',
|
7
|
+
'.png' => 'image/png',
|
8
|
+
'.jpg' => 'image/jpeg',
|
9
|
+
'.jpeg' => 'image/jpeg',
|
10
|
+
'.gif' => 'image/gif',
|
11
|
+
}
|
12
|
+
|
13
|
+
attr_reader :absolute_path, :relative_path
|
14
|
+
|
15
|
+
def initialize(absolute_path, relative_path)
|
16
|
+
@absolute_path = absolute_path
|
17
|
+
@relative_path = relative_path
|
18
|
+
end
|
19
|
+
|
20
|
+
def get(request, response)
|
21
|
+
extension = ::File.extname(absolute_path)
|
22
|
+
response.headers['Content-Type'] = MIME_TYPES[extension] || 'text/html'
|
23
|
+
response.body = ::File.read(absolute_path)
|
24
|
+
end
|
25
|
+
|
26
|
+
def ==(other)
|
27
|
+
return false unless other.class == self.class
|
28
|
+
absolute_path == other.absolute_path && relative_path == other.relative_path
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,73 @@
|
|
1
|
+
module JsTestCore
|
2
|
+
module Resources
|
3
|
+
class Runners
|
4
|
+
class FirefoxRunner
|
5
|
+
class << self
|
6
|
+
def resume(suite_id, text)
|
7
|
+
runner = instances.delete(suite_id)
|
8
|
+
runner.finalize(text)
|
9
|
+
end
|
10
|
+
|
11
|
+
def register_instance(runner)
|
12
|
+
instances[runner.suite_id] = runner
|
13
|
+
end
|
14
|
+
|
15
|
+
protected
|
16
|
+
def instances
|
17
|
+
@instances ||= {}
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
include FileUtils
|
22
|
+
attr_reader :profile_dir, :connection, :driver, :response
|
23
|
+
|
24
|
+
def initialize
|
25
|
+
profile_base = "#{::Dir.tmpdir}/js_test_core/firefox"
|
26
|
+
mkdir_p profile_base
|
27
|
+
@profile_dir = "#{profile_base}/#{Time.now.to_i}"
|
28
|
+
@connection = Server.connection
|
29
|
+
end
|
30
|
+
|
31
|
+
def post(request, response)
|
32
|
+
@response = response
|
33
|
+
|
34
|
+
spec_url = (request && request['spec_url']) ? request['spec_url'] : spec_suite_url
|
35
|
+
parsed_spec_url = URI.parse(spec_url)
|
36
|
+
selenium_port = (request['selenium_port'] || 4444).to_i
|
37
|
+
@driver = Selenium::SeleniumDriver.new(
|
38
|
+
request['selenium_host'] || 'localhost',
|
39
|
+
selenium_port,
|
40
|
+
'*firefox',
|
41
|
+
"#{parsed_spec_url.scheme}://#{parsed_spec_url.host}:#{parsed_spec_url.port}"
|
42
|
+
)
|
43
|
+
begin
|
44
|
+
driver.start
|
45
|
+
rescue Errno::ECONNREFUSED => e
|
46
|
+
raise Errno::ECONNREFUSED, "Cannot connect to Selenium Server on port #{selenium_port}. To start the selenium server, run `selenium`."
|
47
|
+
end
|
48
|
+
Thread.start do
|
49
|
+
driver.open(spec_url)
|
50
|
+
end
|
51
|
+
response.status = 200
|
52
|
+
FirefoxRunner.register_instance self
|
53
|
+
end
|
54
|
+
|
55
|
+
def finalize(text)
|
56
|
+
driver.stop
|
57
|
+
response.body = text
|
58
|
+
connection.send_body(response)
|
59
|
+
end
|
60
|
+
|
61
|
+
def suite_id
|
62
|
+
driver.session_id
|
63
|
+
end
|
64
|
+
|
65
|
+
protected
|
66
|
+
|
67
|
+
def spec_suite_url
|
68
|
+
"#{Server.root_url}/specs"
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
@@ -0,0 +1,50 @@
|
|
1
|
+
module JsTestCore
|
2
|
+
module Resources
|
3
|
+
module Specs
|
4
|
+
class SpecDirSuperclass < ::JsTestCore::Resources::Dir
|
5
|
+
def get(request, response)
|
6
|
+
raise NotImplementedError, "#{self.class}#get needs to be implemented"
|
7
|
+
end
|
8
|
+
end
|
9
|
+
|
10
|
+
class SpecDir < SpecDirSuperclass
|
11
|
+
def spec_files
|
12
|
+
glob("/**/*_spec.js")
|
13
|
+
end
|
14
|
+
|
15
|
+
def locate(name)
|
16
|
+
if file = file(name)
|
17
|
+
file
|
18
|
+
elsif subdir = subdir(name)
|
19
|
+
subdir
|
20
|
+
elsif spec_file = spec_file(name)
|
21
|
+
spec_file
|
22
|
+
else
|
23
|
+
base_path = "#{relative_path}/#{name}"
|
24
|
+
raise "No file or directory found at #{base_path} or spec found at #{base_path}.js."
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
protected
|
29
|
+
|
30
|
+
def subdir(name)
|
31
|
+
absolute_dir_path, relative_dir_path = determine_child_paths(name)
|
32
|
+
if ::File.directory?(absolute_dir_path)
|
33
|
+
SpecDir.new(absolute_dir_path, relative_dir_path)
|
34
|
+
else
|
35
|
+
nil
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
def spec_file(name)
|
40
|
+
absolute_file_path, relative_file_path = determine_child_paths("#{name}.js")
|
41
|
+
if ::File.exists?(absolute_file_path) && !::File.directory?(absolute_file_path)
|
42
|
+
SpecFile.new(absolute_file_path, relative_file_path)
|
43
|
+
else
|
44
|
+
nil
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|