Rearrange, start adding specs.
This commit is contained in:
parent
0c8258996e
commit
e4a5d567e0
4
Rakefile
4
Rakefile
|
@ -13,7 +13,7 @@ end
|
||||||
|
|
||||||
namespace :jasmine do
|
namespace :jasmine do
|
||||||
# require 'jasmine'
|
# require 'jasmine'
|
||||||
require 'spec/jasmine_self_test_runner'
|
require 'spec/jasmine_self_test_config'
|
||||||
|
|
||||||
# desc "Run continuous integration tests"
|
# desc "Run continuous integration tests"
|
||||||
# require "spec"
|
# require "spec"
|
||||||
|
@ -28,7 +28,7 @@ namespace :jasmine do
|
||||||
puts "your tests are here:"
|
puts "your tests are here:"
|
||||||
puts " http://localhost:8888/run.html"
|
puts " http://localhost:8888/run.html"
|
||||||
|
|
||||||
JasmineSelfTestRunner.new.start_server
|
JasmineSelfTestConfig.new.start_server
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -1,3 +1,6 @@
|
||||||
|
require 'jasmine/base'
|
||||||
|
require 'jasmine/config'
|
||||||
|
require 'jasmine/server'
|
||||||
|
|
||||||
require 'jasmine/jasmine_helper'
|
require 'jasmine/jasmine_helper'
|
||||||
require 'jasmine/jasmine_runner'
|
|
||||||
require 'jasmine/jasmine_spec_builder'
|
require 'jasmine/jasmine_spec_builder'
|
|
@ -0,0 +1,63 @@
|
||||||
|
require 'socket'
|
||||||
|
require 'erb'
|
||||||
|
require 'json'
|
||||||
|
|
||||||
|
module Jasmine
|
||||||
|
def self.root
|
||||||
|
File.expand_path(File.join(File.dirname(__FILE__), '../../jasmine'))
|
||||||
|
end
|
||||||
|
|
||||||
|
# this seemingly-over-complex method is necessary to get an open port on at least some of our Macs
|
||||||
|
def self.open_socket_on_unused_port
|
||||||
|
infos = Socket::getaddrinfo("localhost", nil, Socket::AF_UNSPEC, Socket::SOCK_STREAM, 0, Socket::AI_PASSIVE)
|
||||||
|
families = Hash[*infos.collect { |af, *_| af }.uniq.zip([]).flatten]
|
||||||
|
|
||||||
|
return TCPServer.open('0.0.0.0', 0) if families.has_key?('AF_INET')
|
||||||
|
return TCPServer.open('::', 0) if families.has_key?('AF_INET6')
|
||||||
|
return TCPServer.open(0)
|
||||||
|
end
|
||||||
|
|
||||||
|
def self.find_unused_port
|
||||||
|
socket = open_socket_on_unused_port
|
||||||
|
port = socket.addr[1]
|
||||||
|
socket.close
|
||||||
|
port
|
||||||
|
end
|
||||||
|
|
||||||
|
def self.server_is_listening_on(hostname, port)
|
||||||
|
require 'socket'
|
||||||
|
begin
|
||||||
|
socket = TCPSocket.open(hostname, port)
|
||||||
|
rescue Errno::ECONNREFUSED
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
socket.close
|
||||||
|
true
|
||||||
|
end
|
||||||
|
|
||||||
|
def self.wait_for_listener(port, name = "required process", seconds_to_wait = 10)
|
||||||
|
time_out_at = Time.now + seconds_to_wait
|
||||||
|
until server_is_listening_on "localhost", port
|
||||||
|
sleep 0.1
|
||||||
|
puts "Waiting for #{name} on #{port}..."
|
||||||
|
raise "#{name} didn't show up on port #{port} after #{seconds_to_wait} seconds." if Time.now > time_out_at
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def self.kill_process_group(process_group_id, signal="TERM")
|
||||||
|
Process.kill signal, -process_group_id # negative pid means kill process group. (see man 2 kill)
|
||||||
|
end
|
||||||
|
|
||||||
|
def self.cachebust(files, root_dir="", replace=nil, replace_with=nil)
|
||||||
|
require 'digest/md5'
|
||||||
|
files.collect do |file_name|
|
||||||
|
real_file_name = replace && replace_with ? file_name.sub(replace, replace_with) : file_name
|
||||||
|
begin
|
||||||
|
digest = Digest::MD5.hexdigest(File.read("#{root_dir}#{real_file_name}"))
|
||||||
|
rescue
|
||||||
|
digest = "MISSING-FILE"
|
||||||
|
end
|
||||||
|
"#{file_name}?cachebust=#{digest}"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -0,0 +1,74 @@
|
||||||
|
module Jasmine
|
||||||
|
class Config
|
||||||
|
def initialize(options = {})
|
||||||
|
require 'selenium_rc'
|
||||||
|
@selenium_jar_path = SeleniumRC::Server.allocate.jar_path
|
||||||
|
@options = options
|
||||||
|
|
||||||
|
@browser = options[:browser] ? options.delete(:browser) : 'firefox'
|
||||||
|
@selenium_pid = nil
|
||||||
|
@jasmine_server_pid = nil
|
||||||
|
end
|
||||||
|
|
||||||
|
def start_server(port = 8888)
|
||||||
|
Jasmine::Server.new(port, self).start
|
||||||
|
end
|
||||||
|
|
||||||
|
def start
|
||||||
|
start_servers
|
||||||
|
@client = Jasmine::SimpleClient.new("localhost", @selenium_server_port, "*#{@browser}", "http://localhost:#{@jasmine_server_port}/")
|
||||||
|
@client.connect
|
||||||
|
end
|
||||||
|
|
||||||
|
def stop
|
||||||
|
@client.disconnect
|
||||||
|
stop_servers
|
||||||
|
end
|
||||||
|
|
||||||
|
def start_servers
|
||||||
|
@jasmine_server_port = Jasmine::find_unused_port
|
||||||
|
@selenium_server_port = Jasmine::find_unused_port
|
||||||
|
|
||||||
|
@selenium_pid = fork do
|
||||||
|
Process.setpgrp
|
||||||
|
exec "java -jar #{@selenium_jar_path} -port #{@selenium_server_port} > /dev/null 2>&1"
|
||||||
|
end
|
||||||
|
puts "selenium started. pid is #{@selenium_pid}"
|
||||||
|
|
||||||
|
@jasmine_server_pid = fork do
|
||||||
|
Process.setpgrp
|
||||||
|
Jasmine::Server.start(@jasmine_server_port, spec_files, @options)
|
||||||
|
exit! 0
|
||||||
|
end
|
||||||
|
puts "jasmine server started. pid is #{@jasmine_server_pid}"
|
||||||
|
|
||||||
|
Jasmine::wait_for_listener(@selenium_server_port, "selenium server")
|
||||||
|
Jasmine::wait_for_listener(@jasmine_server_port, "jasmine server")
|
||||||
|
end
|
||||||
|
|
||||||
|
def stop_servers
|
||||||
|
puts "shutting down the servers..."
|
||||||
|
Jasmine::kill_process_group(@selenium_pid) if @selenium_pid
|
||||||
|
Jasmine::kill_process_group(@jasmine_server_pid) if @jasmine_server_pid
|
||||||
|
end
|
||||||
|
|
||||||
|
def run
|
||||||
|
begin
|
||||||
|
start
|
||||||
|
puts "servers are listening on their ports -- running the test script..."
|
||||||
|
tests_passed = @client.run
|
||||||
|
ensure
|
||||||
|
stop
|
||||||
|
end
|
||||||
|
return tests_passed
|
||||||
|
end
|
||||||
|
|
||||||
|
def eval_js(script)
|
||||||
|
@client.eval_js(script)
|
||||||
|
end
|
||||||
|
|
||||||
|
def mappings
|
||||||
|
raise "You need to declare a mappings method in #{self.class}!"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -1,302 +1,3 @@
|
||||||
require 'socket'
|
|
||||||
require 'erb'
|
|
||||||
require 'json'
|
|
||||||
|
|
||||||
module Jasmine
|
module Jasmine
|
||||||
def self.root
|
|
||||||
File.expand_path(File.join(File.dirname(__FILE__), '../../jasmine'))
|
|
||||||
end
|
|
||||||
|
|
||||||
# this seemingly-over-complex method is necessary to get an open port on at least some of our Macs
|
|
||||||
def self.open_socket_on_unused_port
|
|
||||||
infos = Socket::getaddrinfo("localhost", nil, Socket::AF_UNSPEC, Socket::SOCK_STREAM, 0, Socket::AI_PASSIVE)
|
|
||||||
families = Hash[*infos.collect { |af, *_| af }.uniq.zip([]).flatten]
|
|
||||||
|
|
||||||
return TCPServer.open('0.0.0.0', 0) if families.has_key?('AF_INET')
|
|
||||||
return TCPServer.open('::', 0) if families.has_key?('AF_INET6')
|
|
||||||
return TCPServer.open(0)
|
|
||||||
end
|
|
||||||
|
|
||||||
def self.find_unused_port
|
|
||||||
socket = open_socket_on_unused_port
|
|
||||||
port = socket.addr[1]
|
|
||||||
socket.close
|
|
||||||
port
|
|
||||||
end
|
|
||||||
|
|
||||||
def self.server_is_listening_on(hostname, port)
|
|
||||||
require 'socket'
|
|
||||||
begin
|
|
||||||
socket = TCPSocket.open(hostname, port)
|
|
||||||
rescue Errno::ECONNREFUSED
|
|
||||||
return false
|
|
||||||
end
|
|
||||||
socket.close
|
|
||||||
true
|
|
||||||
end
|
|
||||||
|
|
||||||
def self.wait_for_listener(port, name = "required process", seconds_to_wait = 10)
|
|
||||||
time_out_at = Time.now + seconds_to_wait
|
|
||||||
until server_is_listening_on "localhost", port
|
|
||||||
sleep 0.1
|
|
||||||
puts "Waiting for #{name} on #{port}..."
|
|
||||||
raise "#{name} didn't show up on port #{port} after #{seconds_to_wait} seconds." if Time.now > time_out_at
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def self.kill_process_group(process_group_id, signal="TERM")
|
|
||||||
Process.kill signal, -process_group_id # negative pid means kill process group. (see man 2 kill)
|
|
||||||
end
|
|
||||||
|
|
||||||
def self.cachebust(files, root_dir="", replace=nil, replace_with=nil)
|
|
||||||
require 'digest/md5'
|
|
||||||
files.collect do |file_name|
|
|
||||||
real_file_name = replace && replace_with ? file_name.sub(replace, replace_with) : file_name
|
|
||||||
begin
|
|
||||||
digest = Digest::MD5.hexdigest(File.read("#{root_dir}#{real_file_name}"))
|
|
||||||
rescue
|
|
||||||
digest = "MISSING-FILE"
|
|
||||||
end
|
|
||||||
"#{file_name}?cachebust=#{digest}"
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
class RunAdapter
|
|
||||||
def initialize(spec_files_or_proc, options = {})
|
|
||||||
@spec_files_or_proc = Jasmine.files(spec_files_or_proc) || []
|
|
||||||
@jasmine_files = Jasmine.files(options[:jasmine_files]) || [
|
|
||||||
"/__JASMINE_ROOT__/lib/" + File.basename(Dir.glob("#{Jasmine.root}/lib/jasmine*.js").first),
|
|
||||||
"/__JASMINE_ROOT__/lib/TrivialReporter.js",
|
|
||||||
"/__JASMINE_ROOT__/lib/json2.js",
|
|
||||||
"/__JASMINE_ROOT__/lib/consolex.js",
|
|
||||||
]
|
|
||||||
@stylesheets = ["/__JASMINE_ROOT__/lib/jasmine.css"] + (Jasmine.files(options[:stylesheets]) || [])
|
|
||||||
@spec_helpers = Jasmine.files(options[:spec_helpers]) || []
|
|
||||||
end
|
|
||||||
|
|
||||||
def call(env)
|
|
||||||
run
|
|
||||||
end
|
|
||||||
|
|
||||||
def run
|
|
||||||
stylesheets = @stylesheets
|
|
||||||
spec_helpers = @spec_helpers
|
|
||||||
spec_files = @spec_files_or_proc
|
|
||||||
|
|
||||||
jasmine_files = @jasmine_files
|
|
||||||
jasmine_files = jasmine_files.call if jasmine_files.respond_to?(:call)
|
|
||||||
|
|
||||||
css_files = @stylesheets
|
|
||||||
|
|
||||||
|
|
||||||
body = ERB.new(File.read(File.join(File.dirname(__FILE__), "run.html"))).result(binding)
|
|
||||||
[
|
|
||||||
200,
|
|
||||||
{ 'Content-Type' => 'text/html' },
|
|
||||||
body
|
|
||||||
]
|
|
||||||
end
|
|
||||||
|
|
||||||
|
|
||||||
end
|
|
||||||
|
|
||||||
class Redirect
|
|
||||||
def initialize(url)
|
|
||||||
@url = url
|
|
||||||
end
|
|
||||||
|
|
||||||
def call(env)
|
|
||||||
[
|
|
||||||
302,
|
|
||||||
{ 'Location' => @url },
|
|
||||||
[]
|
|
||||||
]
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
class JsAlert
|
|
||||||
def call(env)
|
|
||||||
[
|
|
||||||
200,
|
|
||||||
{ 'Content-Type' => 'application/javascript' },
|
|
||||||
"document.write('<p>Couldn\\'t load #{env["PATH_INFO"]}!</p>');"
|
|
||||||
]
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
class FocusedSuite
|
|
||||||
def initialize(spec_files_or_proc, options)
|
|
||||||
@spec_files_or_proc = Jasmine.files(spec_files_or_proc) || []
|
|
||||||
@options = options
|
|
||||||
end
|
|
||||||
|
|
||||||
def call(env)
|
|
||||||
spec_files = @spec_files_or_proc
|
|
||||||
matching_specs = spec_files.select {|spec_file| spec_file =~ /#{Regexp.escape(env["PATH_INFO"])}/ }.compact
|
|
||||||
if !matching_specs.empty?
|
|
||||||
run_adapter = Jasmine::RunAdapter.new(matching_specs, @options)
|
|
||||||
run_adapter.run
|
|
||||||
else
|
|
||||||
[
|
|
||||||
200,
|
|
||||||
{ 'Content-Type' => 'application/javascript' },
|
|
||||||
"document.write('<p>Couldn\\'t find any specs matching #{env["PATH_INFO"]}!</p>');"
|
|
||||||
]
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
end
|
|
||||||
|
|
||||||
class SimpleServer
|
|
||||||
def self.start(port, spec_files_or_proc, options = {})
|
|
||||||
require 'thin'
|
|
||||||
config = {
|
|
||||||
'/__suite__' => Jasmine::FocusedSuite.new(spec_files_or_proc, options),
|
|
||||||
'/run.html' => Jasmine::Redirect.new('/'),
|
|
||||||
'/' => Jasmine::RunAdapter.new(spec_files_or_proc, options)
|
|
||||||
}
|
|
||||||
|
|
||||||
raise "Need :mappings!" unless options[:mappings]
|
|
||||||
options[:mappings].each do |from, to|
|
|
||||||
config[from] = Rack::File.new(to)
|
|
||||||
end
|
|
||||||
|
|
||||||
config["/__JASMINE_ROOT__"] = Rack::File.new(Jasmine.root)
|
|
||||||
|
|
||||||
app = Rack::Cascade.new([
|
|
||||||
Rack::URLMap.new(config),
|
|
||||||
JsAlert.new
|
|
||||||
])
|
|
||||||
|
|
||||||
begin
|
|
||||||
Thin::Server.start('0.0.0.0', port, app)
|
|
||||||
rescue RuntimeError => e
|
|
||||||
raise e unless e.message == 'no acceptor'
|
|
||||||
raise RuntimeError.new("A server is already running on port #{port}")
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
class SimpleClient
|
|
||||||
def initialize(selenium_host, selenium_port, selenium_browser_start_command, http_address)
|
|
||||||
require 'selenium/client'
|
|
||||||
@driver = Selenium::Client::Driver.new(
|
|
||||||
selenium_host,
|
|
||||||
selenium_port,
|
|
||||||
selenium_browser_start_command,
|
|
||||||
http_address
|
|
||||||
)
|
|
||||||
@http_address = http_address
|
|
||||||
end
|
|
||||||
|
|
||||||
def tests_have_finished?
|
|
||||||
@driver.get_eval("window.jasmine.getEnv().currentRunner.finished") == "true"
|
|
||||||
end
|
|
||||||
|
|
||||||
def connect
|
|
||||||
@driver.start
|
|
||||||
@driver.open("/")
|
|
||||||
end
|
|
||||||
|
|
||||||
def disconnect
|
|
||||||
@driver.stop
|
|
||||||
end
|
|
||||||
|
|
||||||
def run
|
|
||||||
until tests_have_finished? do
|
|
||||||
sleep 0.1
|
|
||||||
end
|
|
||||||
|
|
||||||
puts @driver.get_eval("window.results()")
|
|
||||||
failed_count = @driver.get_eval("window.jasmine.getEnv().currentRunner.results().failedCount").to_i
|
|
||||||
failed_count == 0
|
|
||||||
end
|
|
||||||
|
|
||||||
def eval_js(script)
|
|
||||||
escaped_script = "'" + script.gsub(/(['\\])/) { '\\' + $1 } + "'"
|
|
||||||
|
|
||||||
result = @driver.get_eval(" try { eval(#{escaped_script}, window); } catch(err) { window.eval(#{escaped_script}); }")
|
|
||||||
JSON.parse("[#{result}]")[0]
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
class Runner
|
|
||||||
def initialize(options = {})
|
|
||||||
require 'selenium_rc'
|
|
||||||
@selenium_jar_path = SeleniumRC::Server.allocate.jar_path
|
|
||||||
@spec_files = spec_files
|
|
||||||
@options = options
|
|
||||||
|
|
||||||
@browser = options[:browser] ? options.delete(:browser) : 'firefox'
|
|
||||||
@selenium_pid = nil
|
|
||||||
@jasmine_server_pid = nil
|
|
||||||
end
|
|
||||||
|
|
||||||
def start_server(port = 8888)
|
|
||||||
p spec_files
|
|
||||||
Jasmine::SimpleServer.start(port, lambda { spec_files }, :mappings => {
|
|
||||||
"/spec" => spec_dir
|
|
||||||
})
|
|
||||||
end
|
|
||||||
|
|
||||||
def start
|
|
||||||
start_servers
|
|
||||||
@client = Jasmine::SimpleClient.new("localhost", @selenium_server_port, "*#{@browser}", "http://localhost:#{@jasmine_server_port}/")
|
|
||||||
@client.connect
|
|
||||||
end
|
|
||||||
|
|
||||||
def stop
|
|
||||||
@client.disconnect
|
|
||||||
stop_servers
|
|
||||||
end
|
|
||||||
|
|
||||||
def start_servers
|
|
||||||
@jasmine_server_port = Jasmine::find_unused_port
|
|
||||||
@selenium_server_port = Jasmine::find_unused_port
|
|
||||||
|
|
||||||
@selenium_pid = fork do
|
|
||||||
Process.setpgrp
|
|
||||||
exec "java -jar #{@selenium_jar_path} -port #{@selenium_server_port} > /dev/null 2>&1"
|
|
||||||
end
|
|
||||||
puts "selenium started. pid is #{@selenium_pid}"
|
|
||||||
|
|
||||||
@jasmine_server_pid = fork do
|
|
||||||
Process.setpgrp
|
|
||||||
Jasmine::SimpleServer.start(@jasmine_server_port, @spec_files, @options)
|
|
||||||
exit! 0
|
|
||||||
end
|
|
||||||
puts "jasmine server started. pid is #{@jasmine_server_pid}"
|
|
||||||
|
|
||||||
Jasmine::wait_for_listener(@selenium_server_port, "selenium server")
|
|
||||||
Jasmine::wait_for_listener(@jasmine_server_port, "jasmine server")
|
|
||||||
end
|
|
||||||
|
|
||||||
def stop_servers
|
|
||||||
puts "shutting down the servers..."
|
|
||||||
Jasmine::kill_process_group(@selenium_pid) if @selenium_pid
|
|
||||||
Jasmine::kill_process_group(@jasmine_server_pid) if @jasmine_server_pid
|
|
||||||
end
|
|
||||||
|
|
||||||
def run
|
|
||||||
begin
|
|
||||||
start
|
|
||||||
puts "servers are listening on their ports -- running the test script..."
|
|
||||||
tests_passed = @client.run
|
|
||||||
ensure
|
|
||||||
stop
|
|
||||||
end
|
|
||||||
return tests_passed
|
|
||||||
end
|
|
||||||
|
|
||||||
def eval_js(script)
|
|
||||||
@client.eval_js(script)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def self.files(f)
|
|
||||||
result = f
|
|
||||||
result = result.call if result.respond_to?(:call)
|
|
||||||
result
|
|
||||||
end
|
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
|
@ -0,0 +1,179 @@
|
||||||
|
module Jasmine
|
||||||
|
class RunAdapter
|
||||||
|
def initialize(spec_files_or_proc, options = {})
|
||||||
|
@spec_files_or_proc = Jasmine.files(spec_files_or_proc) || []
|
||||||
|
@jasmine_files = Jasmine.files(options[:jasmine_files]) || [
|
||||||
|
"/__JASMINE_ROOT__/lib/" + File.basename(Dir.glob("#{Jasmine.root}/lib/jasmine*.js").first),
|
||||||
|
"/__JASMINE_ROOT__/lib/TrivialReporter.js",
|
||||||
|
"/__JASMINE_ROOT__/lib/json2.js",
|
||||||
|
"/__JASMINE_ROOT__/lib/consolex.js",
|
||||||
|
]
|
||||||
|
@stylesheets = ["/__JASMINE_ROOT__/lib/jasmine.css"] + (Jasmine.files(options[:stylesheets]) || [])
|
||||||
|
@spec_helpers = Jasmine.files(options[:spec_helpers]) || []
|
||||||
|
end
|
||||||
|
|
||||||
|
def call(env)
|
||||||
|
run
|
||||||
|
end
|
||||||
|
|
||||||
|
def run
|
||||||
|
stylesheets = @stylesheets
|
||||||
|
spec_helpers = @spec_helpers
|
||||||
|
spec_files = @spec_files_or_proc
|
||||||
|
|
||||||
|
jasmine_files = @jasmine_files
|
||||||
|
jasmine_files = jasmine_files.call if jasmine_files.respond_to?(:call)
|
||||||
|
|
||||||
|
css_files = @stylesheets
|
||||||
|
|
||||||
|
|
||||||
|
body = ERB.new(File.read(File.join(File.dirname(__FILE__), "run.html"))).result(binding)
|
||||||
|
[
|
||||||
|
200,
|
||||||
|
{ 'Content-Type' => 'text/html' },
|
||||||
|
body
|
||||||
|
]
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
class Redirect
|
||||||
|
def initialize(url)
|
||||||
|
@url = url
|
||||||
|
end
|
||||||
|
|
||||||
|
def call(env)
|
||||||
|
[
|
||||||
|
302,
|
||||||
|
{ 'Location' => @url },
|
||||||
|
[]
|
||||||
|
]
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
class JsAlert
|
||||||
|
def call(env)
|
||||||
|
[
|
||||||
|
200,
|
||||||
|
{ 'Content-Type' => 'application/javascript' },
|
||||||
|
"document.write('<p>Couldn\\'t load #{env["PATH_INFO"]}!</p>');"
|
||||||
|
]
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
class FocusedSuite
|
||||||
|
def initialize(config)
|
||||||
|
@config = config
|
||||||
|
# @spec_files_or_proc = Jasmine.files(spec_files_or_proc) || []
|
||||||
|
# @options = options
|
||||||
|
end
|
||||||
|
|
||||||
|
def call(env)
|
||||||
|
spec_files = Jasmine.files(@config.spec_files_or_proc)
|
||||||
|
matching_specs = spec_files.select {|spec_file| spec_file =~ /#{Regexp.escape(env["PATH_INFO"])}/ }.compact
|
||||||
|
if !matching_specs.empty?
|
||||||
|
run_adapter = Jasmine::RunAdapter.new(matching_specs, @options)
|
||||||
|
run_adapter.run
|
||||||
|
else
|
||||||
|
[
|
||||||
|
200,
|
||||||
|
{ 'Content-Type' => 'application/javascript' },
|
||||||
|
"document.write('<p>Couldn\\'t find any specs matching #{env["PATH_INFO"]}!</p>');"
|
||||||
|
]
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
def self.files(f)
|
||||||
|
result = f
|
||||||
|
result = result.call if result.respond_to?(:call)
|
||||||
|
result
|
||||||
|
end
|
||||||
|
|
||||||
|
class Server
|
||||||
|
attr_reader :thin
|
||||||
|
|
||||||
|
def initialize(port, config)
|
||||||
|
@port = port
|
||||||
|
@config = config
|
||||||
|
|
||||||
|
require 'thin'
|
||||||
|
thin_config = {
|
||||||
|
'/__suite__' => Jasmine::FocusedSuite.new(@config),
|
||||||
|
'/run.html' => Jasmine::Redirect.new('/'),
|
||||||
|
'/' => Jasmine::RunAdapter.new(@config)
|
||||||
|
}
|
||||||
|
|
||||||
|
@config.mappings.each do |from, to|
|
||||||
|
thin_config[from] = Rack::File.new(to)
|
||||||
|
end
|
||||||
|
|
||||||
|
thin_config["/__JASMINE_ROOT__"] = Rack::File.new(Jasmine.root)
|
||||||
|
|
||||||
|
app = Rack::Cascade.new([
|
||||||
|
Rack::URLMap.new(thin_config),
|
||||||
|
JsAlert.new
|
||||||
|
])
|
||||||
|
|
||||||
|
@thin = Thin::Server.new('0.0.0.0', @port, app)
|
||||||
|
end
|
||||||
|
|
||||||
|
def start
|
||||||
|
begin
|
||||||
|
thin.start
|
||||||
|
rescue RuntimeError => e
|
||||||
|
raise e unless e.message == 'no acceptor'
|
||||||
|
raise RuntimeError.new("A server is already running on port #{@port}")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def stop
|
||||||
|
thin.stop
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
class SimpleClient
|
||||||
|
def initialize(selenium_host, selenium_port, selenium_browser_start_command, http_address)
|
||||||
|
require 'selenium/client'
|
||||||
|
@driver = Selenium::Client::Driver.new(
|
||||||
|
selenium_host,
|
||||||
|
selenium_port,
|
||||||
|
selenium_browser_start_command,
|
||||||
|
http_address
|
||||||
|
)
|
||||||
|
@http_address = http_address
|
||||||
|
end
|
||||||
|
|
||||||
|
def tests_have_finished?
|
||||||
|
@driver.get_eval("window.jasmine.getEnv().currentRunner.finished") == "true"
|
||||||
|
end
|
||||||
|
|
||||||
|
def connect
|
||||||
|
@driver.start
|
||||||
|
@driver.open("/")
|
||||||
|
end
|
||||||
|
|
||||||
|
def disconnect
|
||||||
|
@driver.stop
|
||||||
|
end
|
||||||
|
|
||||||
|
def run
|
||||||
|
until tests_have_finished? do
|
||||||
|
sleep 0.1
|
||||||
|
end
|
||||||
|
|
||||||
|
puts @driver.get_eval("window.results()")
|
||||||
|
failed_count = @driver.get_eval("window.jasmine.getEnv().currentRunner.results().failedCount").to_i
|
||||||
|
failed_count == 0
|
||||||
|
end
|
||||||
|
|
||||||
|
def eval_js(script)
|
||||||
|
escaped_script = "'" + script.gsub(/(['\\])/) { '\\' + $1 } + "'"
|
||||||
|
|
||||||
|
result = @driver.get_eval(" try { eval(#{escaped_script}, window); } catch(err) { window.eval(#{escaped_script}); }")
|
||||||
|
JSON.parse("[#{result}]")[0]
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -1,6 +1,6 @@
|
||||||
require 'jasmine'
|
require 'jasmine'
|
||||||
|
|
||||||
class JasmineSelfTestRunner < Jasmine::Runner
|
class JasmineSelfTestConfig < Jasmine::Config
|
||||||
def proj_root
|
def proj_root
|
||||||
File.expand_path(File.join(File.dirname(__FILE__), ".."))
|
File.expand_path(File.join(File.dirname(__FILE__), ".."))
|
||||||
end
|
end
|
||||||
|
@ -20,6 +20,12 @@ class JasmineSelfTestRunner < Jasmine::Runner
|
||||||
def spec_files
|
def spec_files
|
||||||
Dir.glob(File.join(spec_dir, "**/*[Ss]pec.js")).collect { |f| f.sub("#{spec_dir}/", "") }
|
Dir.glob(File.join(spec_dir, "**/*[Ss]pec.js")).collect { |f| f.sub("#{spec_dir}/", "") }
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def mappings
|
||||||
|
{
|
||||||
|
"/spec" => spec_dir
|
||||||
|
}
|
||||||
|
end
|
||||||
#
|
#
|
||||||
# def specs
|
# def specs
|
||||||
# Jasmine.cachebust(spec_files).collect {|f| f.sub(spec_dir, "/spec")}
|
# Jasmine.cachebust(spec_files).collect {|f| f.sub(spec_dir, "/spec")}
|
|
@ -1,4 +1,4 @@
|
||||||
require 'jasmine_self_test_runner'
|
require 'jasmine_self_test_config'
|
||||||
|
|
||||||
jasmine_runner = JasmineSelfTestRunner.new
|
jasmine_runner = JasmineSelfTestRunner.new
|
||||||
spec_builder = Jasmine::SpecBuilder.new(jasmine_runner)
|
spec_builder = Jasmine::SpecBuilder.new(jasmine_runner)
|
||||||
|
|
|
@ -0,0 +1,51 @@
|
||||||
|
require File.expand_path(File.join(File.dirname(__FILE__), "spec_helper"))
|
||||||
|
|
||||||
|
def read(body)
|
||||||
|
return body if body.is_a?(String)
|
||||||
|
out = ""
|
||||||
|
body.each {|data| out += data }
|
||||||
|
out
|
||||||
|
end
|
||||||
|
|
||||||
|
describe Jasmine::Server do
|
||||||
|
before(:each) do
|
||||||
|
config = Jasmine::Config.new
|
||||||
|
config.stub!(:mappings).and_return({
|
||||||
|
"/src" => File.join(Jasmine.root, "src"),
|
||||||
|
"/spec" => File.join(Jasmine.root, "spec")
|
||||||
|
})
|
||||||
|
|
||||||
|
@server = Jasmine::Server.new(0, config)
|
||||||
|
@thin_app = @server.thin.app
|
||||||
|
end
|
||||||
|
|
||||||
|
after(:each) do
|
||||||
|
@server.thin.stop if @server && @server.thin.running?
|
||||||
|
end
|
||||||
|
|
||||||
|
it "should serve static files" do
|
||||||
|
code, headers, body = @thin_app.call("PATH_INFO" => "/spec/suites/EnvSpec.js", "SCRIPT_NAME" => "xxx")
|
||||||
|
code.should == 200
|
||||||
|
headers["Content-Type"].should == "application/javascript"
|
||||||
|
read(body).should == File.read(File.join(Jasmine.root, "spec/suites/EnvSpec.js"))
|
||||||
|
end
|
||||||
|
|
||||||
|
it "should serve Jasmine static files under /__JASMINE_ROOT__/" do
|
||||||
|
code, headers, body = @thin_app.call("PATH_INFO" => "/__JASMINE_ROOT__/lib/jasmine.css", "SCRIPT_NAME" => "xxx")
|
||||||
|
code.should == 200
|
||||||
|
headers["Content-Type"].should == "text/css"
|
||||||
|
read(body).should == File.read(File.join(Jasmine.root, "lib/jasmine.css"))
|
||||||
|
end
|
||||||
|
|
||||||
|
it "should redirect /run.html to /" do
|
||||||
|
code, headers, body = @thin_app.call("PATH_INFO" => "/run.html", "SCRIPT_NAME" => "xxx")
|
||||||
|
code.should == 302
|
||||||
|
headers["Location"].should == "/"
|
||||||
|
end
|
||||||
|
|
||||||
|
it "should serve /" do
|
||||||
|
code, headers, body = @thin_app.call("PATH_INFO" => "/", "SCRIPT_NAME" => "xxx")
|
||||||
|
body = read(body)
|
||||||
|
p body
|
||||||
|
end
|
||||||
|
end
|
|
@ -0,0 +1,3 @@
|
||||||
|
require 'spec'
|
||||||
|
|
||||||
|
require File.expand_path(File.join(File.dirname(__FILE__), "../lib/jasmine"))
|
|
@ -17,7 +17,7 @@ namespace :jasmine do
|
||||||
puts "your tests are here:"
|
puts "your tests are here:"
|
||||||
puts " http://localhost:8888/run.html"
|
puts " http://localhost:8888/run.html"
|
||||||
|
|
||||||
Jasmine::SimpleServer.start(8888,
|
Jasmine::Server.start(8888,
|
||||||
File.expand_path(Dir.pwd),
|
File.expand_path(Dir.pwd),
|
||||||
lambda { JasmineHelper.specs },
|
lambda { JasmineHelper.specs },
|
||||||
{ :spec_helpers => JasmineHelper.files + JasmineHelper.spec_helpers,
|
{ :spec_helpers => JasmineHelper.files + JasmineHelper.spec_helpers,
|
||||||
|
|
Loading…
Reference in New Issue