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
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
@@ -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,2 @@
1
+ dir = File.dirname(__FILE__)
2
+ require "#{dir}/rack/commonlogger"
@@ -0,0 +1,5 @@
1
+ Rack::CommonLogger.class_eval do
2
+ def empty?
3
+ @body.empty?
4
+ end
5
+ 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,15 @@
1
+ dir = File.dirname(__FILE__)
2
+
3
+ module JsTestCore
4
+ module Resources
5
+ class Runners
6
+ def locate(name)
7
+ if name == 'firefox'
8
+ FirefoxRunner.new
9
+ else
10
+ raise "Invalid path #{name}"
11
+ end
12
+ end
13
+ end
14
+ end
15
+ 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