Resolve merge conflicts
This commit is contained in:
commit
92e671692f
11
Gemfile
Normal file
11
Gemfile
Normal file
@ -0,0 +1,11 @@
|
||||
gem "rake", "0.8.7"
|
||||
gem "jeweler", "1.4.0"
|
||||
gem "gemcutter", "0.2.1"
|
||||
|
||||
gem "rspec", ">= 1.1.5", :only => :testing
|
||||
gem "rack", ">= 1.0.0", :only => :testing
|
||||
gem "thin", ">= 1.2.4", :only => :testing
|
||||
gem "selenium-rc", ">=2.1.0", :only => :testing
|
||||
gem "selenium-client", ">=1.2.17", :only => :testing
|
||||
|
||||
disable_system_gems
|
66
Rakefile
66
Rakefile
@ -1,27 +1,65 @@
|
||||
require "#{File.dirname(__FILE__)}/vendor/gems/environment"
|
||||
Bundler.require_env :rake
|
||||
|
||||
$LOAD_PATH.unshift File.expand_path("#{File.dirname(__FILE__)}/lib")
|
||||
|
||||
require 'spec'
|
||||
require 'spec/rake/spectask'
|
||||
|
||||
desc "Run all examples"
|
||||
Spec::Rake::SpecTask.new('spec') do |t|
|
||||
t.spec_files = FileList['spec/**/*.rb']
|
||||
end
|
||||
|
||||
namespace :jasmine do
|
||||
# require 'jasmine'
|
||||
require 'spec/jasmine_self_test_config'
|
||||
|
||||
# desc "Run continuous integration tests"
|
||||
# require "spec"
|
||||
# require 'spec/rake/spectask'
|
||||
# Spec::Rake::SpecTask.new(:ci) do |t|
|
||||
# t.spec_opts = ["--color", "--format", "specdoc"]
|
||||
# t.verbose = true
|
||||
# t.spec_files = [JasmineHelper.meta_spec_path]
|
||||
# end
|
||||
|
||||
task :server do
|
||||
puts "your tests are here:"
|
||||
puts " http://localhost:8888/run.html"
|
||||
|
||||
JasmineSelfTestConfig.new.start_server
|
||||
end
|
||||
end
|
||||
|
||||
desc "Run specs via server"
|
||||
task :jasmine => ['jasmine:server']
|
||||
|
||||
|
||||
namespace :jeweler do
|
||||
|
||||
unless File.exists?('jasmine/lib')
|
||||
raise "Jasmine submodule isn't present. Run git submodule init && git submodule update."
|
||||
end
|
||||
|
||||
begin
|
||||
require 'jeweler'
|
||||
require 'rake'
|
||||
Jeweler::Tasks.new do |gemspec|
|
||||
gemspec.name = "jasmine-ruby"
|
||||
gemspec.summary = "Jasmine Ruby"
|
||||
gemspec.description = "Javascript BDD testings"
|
||||
gemspec.name = "jasmine"
|
||||
gemspec.summary = "Jasmine Ruby Runner"
|
||||
gemspec.description = "Javascript BDD test framework"
|
||||
gemspec.email = "ragaskar@gmail.com"
|
||||
gemspec.homepage = "http://github.com/ragaskar/jasmine-ruby"
|
||||
gemspec.description = "Jasmine Ruby"
|
||||
gemspec.authors = ["Rajan Agaskar"]
|
||||
gemspec.files = FileList.new('bin/*', 'lib/**/**', 'jasmine/lib/**', 'tasks/**', 'templates/**')
|
||||
|
||||
gemspec.homepage = "http://github.com/pivotal/jasmine-ruby"
|
||||
gemspec.authors = ["Rajan Agaskar", "Christian Williams"]
|
||||
gemspec.files = FileList.new('bin/jasmine', 'lib/**/**', 'jasmine/lib/**', 'jasmine/contrib/ruby/**', 'tasks/**', 'templates/**')
|
||||
gemspec.add_dependency('rspec', '>= 1.1.5')
|
||||
gemspec.add_dependency('rack', '>= 1.0.0')
|
||||
gemspec.add_dependency('json', '>= 1.1.9')
|
||||
gemspec.add_dependency('pivotal-selenium-rc', '>= 1.11.20090610')
|
||||
gemspec.add_dependency('selenium-client', '>= 1.2.17')
|
||||
gemspec.add_dependency('thin', '= 1.2.4')
|
||||
gemspec.add_dependency('rack', '>= 1.0.0')
|
||||
gemspec.add_dependency('thin', '>= 1.2.4')
|
||||
gemspec.add_dependency('selenium-rc', '>=2.1.0')
|
||||
gemspec.add_dependency('selenium-client', '>=1.2.17')
|
||||
end
|
||||
Jeweler::GemcutterTasks.new
|
||||
rescue LoadError
|
||||
puts "Jeweler not available. Install it with: sudo gem install technicalpickles-jeweler -s http://gems.github.com"
|
||||
end
|
||||
end
|
||||
|
@ -1,5 +1,5 @@
|
||||
---
|
||||
:minor: 2
|
||||
:patch: 0
|
||||
:build:
|
||||
:minor: 1
|
||||
:build:
|
||||
:patch: 3
|
||||
:major: 0
|
||||
|
@ -1,6 +0,0 @@
|
||||
---
|
||||
gems:
|
||||
- name: rake
|
||||
version: 0.8.7
|
||||
- name: jeweler
|
||||
version: 1.4.0
|
2
jasmine
2
jasmine
@ -1 +1 @@
|
||||
Subproject commit 40ff1cb4c8339cce5c799549427d6859eb4480a1
|
||||
Subproject commit 701ee719e6e1e7d9f2ac84707302cb430ac123e4
|
@ -4,12 +4,12 @@
|
||||
# -*- encoding: utf-8 -*-
|
||||
|
||||
Gem::Specification.new do |s|
|
||||
s.name = %q{jasmine-ruby}
|
||||
s.name = %q{jasmine}
|
||||
s.version = "0.1.0"
|
||||
|
||||
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
||||
s.authors = ["Rajan Agaskar"]
|
||||
s.date = %q{2009-12-05}
|
||||
s.date = %q{2009-12-27}
|
||||
s.default_executable = %q{jasmine}
|
||||
s.description = %q{Jasmine Ruby}
|
||||
s.email = %q{ragaskar@gmail.com}
|
||||
@ -24,18 +24,18 @@ Gem::Specification.new do |s|
|
||||
"jasmine/lib/jasmine-0.10.0.js",
|
||||
"jasmine/lib/jasmine.css",
|
||||
"jasmine/lib/json2.js",
|
||||
"lib/jasmine-ruby.rb",
|
||||
"lib/jasmine-ruby/jasmine_helper.rb",
|
||||
"lib/jasmine-ruby/jasmine_meta_spec.rb",
|
||||
"lib/jasmine-ruby/jasmine_runner.rb",
|
||||
"lib/jasmine-ruby/jasmine_spec_builder.rb",
|
||||
"lib/jasmine-ruby/run.html",
|
||||
"lib/jasmine.rb",
|
||||
"lib/jasmine/jasmine_helper.rb",
|
||||
"lib/jasmine/jasmine_meta_spec.rb",
|
||||
"lib/jasmine/jasmine_runner.rb",
|
||||
"lib/jasmine/spec_builder.rb",
|
||||
"lib/jasmine/run.html",
|
||||
"templates/Rakefile",
|
||||
"templates/example_spec.js",
|
||||
"templates/ExampleSpec.js",
|
||||
"templates/jasmine_helper.rb",
|
||||
"templates/spec_helper.js"
|
||||
"templates/SpecHelper.js"
|
||||
]
|
||||
s.homepage = %q{http://github.com/ragaskar/jasmine-ruby}
|
||||
s.homepage = %q{http://github.com/ragaskar/jasmine}
|
||||
s.rdoc_options = ["--charset=UTF-8"]
|
||||
s.require_paths = ["lib"]
|
||||
s.rubygems_version = %q{1.3.5}
|
||||
@ -51,25 +51,16 @@ Gem::Specification.new do |s|
|
||||
if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
|
||||
s.add_runtime_dependency(%q<rspec>, [">= 1.1.5"])
|
||||
s.add_runtime_dependency(%q<rack>, [">= 1.0.0"])
|
||||
s.add_runtime_dependency(%q<json>, [">= 1.1.9"])
|
||||
s.add_runtime_dependency(%q<pivotal-selenium-rc>, [">= 1.11.20090610"])
|
||||
s.add_runtime_dependency(%q<selenium-client>, [">= 1.2.17"])
|
||||
s.add_runtime_dependency(%q<thin>, ["= 1.2.4"])
|
||||
s.add_runtime_dependency(%q<thin>, [">= 1.2.4"])
|
||||
else
|
||||
s.add_dependency(%q<rspec>, [">= 1.1.5"])
|
||||
s.add_dependency(%q<rack>, [">= 1.0.0"])
|
||||
s.add_dependency(%q<json>, [">= 1.1.9"])
|
||||
s.add_dependency(%q<pivotal-selenium-rc>, [">= 1.11.20090610"])
|
||||
s.add_dependency(%q<selenium-client>, [">= 1.2.17"])
|
||||
s.add_dependency(%q<thin>, ["= 1.2.4"])
|
||||
s.add_dependency(%q<thin>, [">= 1.2.4"])
|
||||
end
|
||||
else
|
||||
s.add_dependency(%q<rspec>, [">= 1.1.5"])
|
||||
s.add_dependency(%q<rack>, [">= 1.0.0"])
|
||||
s.add_dependency(%q<json>, [">= 1.1.9"])
|
||||
s.add_dependency(%q<pivotal-selenium-rc>, [">= 1.11.20090610"])
|
||||
s.add_dependency(%q<selenium-client>, [">= 1.2.17"])
|
||||
s.add_dependency(%q<thin>, ["= 1.2.4"])
|
||||
s.add_dependency(%q<thin>, [">= 1.2.4"])
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -1,3 +0,0 @@
|
||||
require 'jasmine-ruby/jasmine_helper'
|
||||
require 'jasmine-ruby/jasmine_runner'
|
||||
require 'jasmine-ruby/jasmine_spec_builder'
|
@ -1,300 +0,0 @@
|
||||
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
|
||||
|
||||
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, root_path, 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)
|
||||
}
|
||||
if (options[:mappings])
|
||||
options[:mappings].each do |from, to|
|
||||
config[from] = Rack::File.new(to)
|
||||
end
|
||||
end
|
||||
|
||||
config["/__JASMINE_ROOT__"] = Rack::File.new(Jasmine.root)
|
||||
|
||||
file_serve_config = {
|
||||
'/' => Rack::File.new(root_path)
|
||||
}
|
||||
|
||||
app = Rack::Cascade.new([
|
||||
Rack::URLMap.new(file_serve_config),
|
||||
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(selenium_jar_path, root_path, spec_files, options={})
|
||||
@root_path = root_path
|
||||
@selenium_jar_path = selenium_jar_path
|
||||
@spec_files = spec_files
|
||||
@options = options
|
||||
|
||||
@browser = options[:browser] ? options[:browser].delete(:browser) : 'firefox'
|
||||
@selenium_pid = nil
|
||||
@jasmine_server_pid = nil
|
||||
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, @root_path, @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
|
7
lib/jasmine.rb
Normal file
7
lib/jasmine.rb
Normal file
@ -0,0 +1,7 @@
|
||||
require 'jasmine/base'
|
||||
require 'jasmine/config'
|
||||
require 'jasmine/server'
|
||||
require 'jasmine/selenium_driver'
|
||||
|
||||
require 'jasmine/jasmine_helper'
|
||||
require 'jasmine/spec_builder'
|
63
lib/jasmine/base.rb
Normal file
63
lib/jasmine/base.rb
Normal file
@ -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
|
120
lib/jasmine/config.rb
Normal file
120
lib/jasmine/config.rb
Normal file
@ -0,0 +1,120 @@
|
||||
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::SeleniumDriver.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
|
||||
|
||||
server = Jasmine::Server.new(@jasmine_server_port, self)
|
||||
|
||||
@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
|
||||
server.start
|
||||
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 stylesheets
|
||||
[]
|
||||
end
|
||||
|
||||
def src_files
|
||||
[]
|
||||
end
|
||||
|
||||
def spec_files
|
||||
raise "You need to declare a spec_files method in #{self.class}!"
|
||||
end
|
||||
|
||||
def match_files(dir, pattern)
|
||||
dir = File.expand_path(dir)
|
||||
Dir.glob(File.join(dir, pattern)).collect {|f| f.sub("#{dir}/", "")}.sort
|
||||
end
|
||||
|
||||
def src_files
|
||||
match_files(src_dir, "**/*.js")
|
||||
end
|
||||
|
||||
def src_path
|
||||
"src"
|
||||
end
|
||||
|
||||
def spec_path
|
||||
"spec"
|
||||
end
|
||||
|
||||
def spec_files
|
||||
match_files(spec_dir, "**/*.js")
|
||||
end
|
||||
|
||||
def mappings
|
||||
{
|
||||
"/" + src_path => src_dir,
|
||||
"/" + spec_path => spec_dir
|
||||
}
|
||||
end
|
||||
|
||||
def js_files
|
||||
src_files.collect {|f| "/" + File.join(src_path, f) } + spec_files.collect {|f| "/" + File.join(spec_path, f) }
|
||||
end
|
||||
|
||||
def spec_files_full_paths
|
||||
spec_files.collect {|spec_file| File.join(spec_dir, spec_file) }
|
||||
end
|
||||
end
|
||||
end
|
@ -34,7 +34,7 @@ class JasmineHelper
|
||||
end
|
||||
|
||||
def self.meta_spec_path
|
||||
File.expand_path(File.join(File.dirname(__FILE__), '..', '..', 'lib', 'jasmine-ruby', 'jasmine_meta_spec.rb'))
|
||||
File.expand_path(File.join(File.dirname(__FILE__), '..', '..', 'lib', 'jasmine', 'jasmine_meta_spec.rb'))
|
||||
end
|
||||
|
||||
def self.files
|
@ -6,7 +6,7 @@ if File.exist?(helper_overrides)
|
||||
require helper_overrides
|
||||
end
|
||||
require File.expand_path(File.join(File.dirname(__FILE__), "jasmine_runner.rb"))
|
||||
require File.expand_path(File.join(File.dirname(__FILE__), "jasmine_spec_builder"))
|
||||
require File.expand_path(File.join(File.dirname(__FILE__), "spec_builder"))
|
||||
|
||||
jasmine_runner = Jasmine::Runner.new(SeleniumRC::Server.new.jar_path,
|
||||
Dir.pwd,
|
@ -11,10 +11,6 @@
|
||||
<script src="<%= jasmine_file %>" type="text/javascript"></script>
|
||||
<% end %>
|
||||
|
||||
<% spec_helpers.each do |spec_helper| %>
|
||||
<script src="<%= spec_helper %>" type="text/javascript"></script>
|
||||
<% end %>
|
||||
|
||||
<script type="text/javascript">
|
||||
var jsApiReporter;
|
||||
(function() {
|
||||
@ -36,8 +32,8 @@
|
||||
})();
|
||||
</script>
|
||||
|
||||
<% spec_files.each do |spec_file| %>
|
||||
<script src="<%= spec_file %>" type="text/javascript"></script>
|
||||
<% js_files.each do |js_file| %>
|
||||
<script src="<%= js_file %>" type="text/javascript"></script>
|
||||
<% end %>
|
||||
|
||||
</head>
|
44
lib/jasmine/selenium_driver.rb
Normal file
44
lib/jasmine/selenium_driver.rb
Normal file
@ -0,0 +1,44 @@
|
||||
module Jasmine
|
||||
class SeleniumDriver
|
||||
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
|
124
lib/jasmine/server.rb
Normal file
124
lib/jasmine/server.rb
Normal file
@ -0,0 +1,124 @@
|
||||
module Jasmine
|
||||
class RunAdapter
|
||||
def initialize(config)
|
||||
@config = config
|
||||
@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",
|
||||
]
|
||||
@jasmine_stylesheets = ["/__JASMINE_ROOT__/lib/jasmine.css"]
|
||||
end
|
||||
|
||||
def call(env)
|
||||
run
|
||||
end
|
||||
|
||||
#noinspection RubyUnusedLocalVariable
|
||||
def run
|
||||
jasmine_files = @jasmine_files
|
||||
css_files = @jasmine_stylesheets + (@config.stylesheets || [])
|
||||
js_files = @config.js_files
|
||||
|
||||
body = ERB.new(File.read(File.join(File.dirname(__FILE__), "run.html.erb"))).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 = spec_files_or_proc || []
|
||||
# @options = options
|
||||
end
|
||||
|
||||
def call(env)
|
||||
spec_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
|
||||
|
||||
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
|
||||
end
|
@ -1,12 +1,13 @@
|
||||
require 'enumerator'
|
||||
module Jasmine
|
||||
|
||||
module Jasmine
|
||||
class SpecBuilder
|
||||
attr_accessor :suites
|
||||
|
||||
def initialize(spec_files, runner)
|
||||
@spec_files = spec_files
|
||||
@runner = runner
|
||||
def initialize(config)
|
||||
@config = config
|
||||
@spec_files = config.spec_files
|
||||
@runner = config
|
||||
@spec_ids = []
|
||||
end
|
||||
|
||||
@ -31,7 +32,7 @@ module Jasmine
|
||||
|
||||
example_name_parts = []
|
||||
previous_indent_level = 0
|
||||
@spec_files.each do |filename|
|
||||
@config.spec_files_full_paths.each do |filename|
|
||||
line_number = 1
|
||||
File.open(filename, "r") do |file|
|
||||
file.readlines.each do |line|
|
53
spec/config_spec.rb
Normal file
53
spec/config_spec.rb
Normal file
@ -0,0 +1,53 @@
|
||||
require File.expand_path(File.join(File.dirname(__FILE__), "spec_helper"))
|
||||
|
||||
describe Jasmine::Config do
|
||||
before(:each) do
|
||||
@template_dir = File.expand_path(File.join(File.dirname(__FILE__), "../templates"))
|
||||
@config = Jasmine::Config.new
|
||||
@config.stub!(:src_dir).and_return(File.join(@template_dir, "public"))
|
||||
@config.stub!(:spec_dir).and_return(File.join(@template_dir, "spec"))
|
||||
end
|
||||
|
||||
it "should provide a list of all src and spec files" do
|
||||
@config.src_files.should == ['javascripts/Example.js']
|
||||
@config.spec_files.should == ['javascript/ExampleSpec.js', 'javascript/SpecHelper.js']
|
||||
end
|
||||
|
||||
it "should provide a list of all spec files with full paths" do
|
||||
@config.spec_files_full_paths.should == [
|
||||
File.join(@template_dir, 'spec/javascript/ExampleSpec.js'),
|
||||
File.join(@template_dir, 'spec/javascript/SpecHelper.js')
|
||||
]
|
||||
end
|
||||
|
||||
it "should provide a list of all js files" do
|
||||
@config.js_files.should == [
|
||||
'/src/javascripts/Example.js',
|
||||
'/spec/javascript/ExampleSpec.js',
|
||||
'/spec/javascript/SpecHelper.js',
|
||||
]
|
||||
end
|
||||
|
||||
it "should provide dir mappings" do
|
||||
@config.mappings.should == {
|
||||
'/src' => @config.src_dir,
|
||||
'/spec' => @config.spec_dir
|
||||
}
|
||||
end
|
||||
|
||||
it "should allow overriding src and spec paths" do
|
||||
@config.stub!(:src_path).and_return("public")
|
||||
@config.stub!(:spec_path).and_return("spekz")
|
||||
|
||||
@config.js_files.should == [
|
||||
'/public/javascripts/Example.js',
|
||||
'/spekz/javascript/ExampleSpec.js',
|
||||
'/spekz/javascript/SpecHelper.js',
|
||||
]
|
||||
|
||||
@config.mappings.should == {
|
||||
'/public' => @config.src_dir,
|
||||
'/spekz' => @config.spec_dir
|
||||
}
|
||||
end
|
||||
end
|
15
spec/jasmine_self_test_config.rb
Normal file
15
spec/jasmine_self_test_config.rb
Normal file
@ -0,0 +1,15 @@
|
||||
require 'jasmine'
|
||||
|
||||
class JasmineSelfTestConfig < Jasmine::Config
|
||||
def proj_root
|
||||
File.expand_path(File.join(File.dirname(__FILE__), ".."))
|
||||
end
|
||||
|
||||
def src_dir
|
||||
File.join(proj_root, 'src')
|
||||
end
|
||||
|
||||
def spec_dir
|
||||
File.join(proj_root, 'jasmine/spec')
|
||||
end
|
||||
end
|
18
spec/jasmine_self_test_spec.rb
Normal file
18
spec/jasmine_self_test_spec.rb
Normal file
@ -0,0 +1,18 @@
|
||||
require File.expand_path(File.join(File.dirname(__FILE__), "spec_helper"))
|
||||
|
||||
require 'jasmine_self_test_config'
|
||||
|
||||
jasmine_config = JasmineSelfTestConfig.new
|
||||
spec_builder = Jasmine::SpecBuilder.new(jasmine_config)
|
||||
|
||||
should_stop = false
|
||||
|
||||
Spec::Runner.configure do |config|
|
||||
config.after(:suite) do
|
||||
spec_builder.stop if should_stop
|
||||
end
|
||||
end
|
||||
|
||||
spec_builder.start
|
||||
should_stop = true
|
||||
spec_builder.declare_suites
|
@ -1,26 +0,0 @@
|
||||
require 'rubygems'
|
||||
require "selenium_rc"
|
||||
|
||||
JASMINE_SPEC_DIR = File.join(File.dirname(__FILE__), "..", "jasmine", "spec")
|
||||
|
||||
require File.expand_path(File.join(File.dirname(__FILE__), "..", "lib", "jasmine-ruby", "jasmine_helper.rb"))
|
||||
require File.expand_path(File.join(JasmineHelper.root, "contrib/ruby/jasmine_spec_builder"))
|
||||
|
||||
jasmine_runner = Jasmine::Runner.new(SeleniumRC::Server.new.jar_path,
|
||||
JasmineHelper.spec_file_urls,
|
||||
JasmineHelper.dir_mappings,
|
||||
:spec_helpers => JasmineHelper.spec_helpers)
|
||||
|
||||
spec_builder = Jasmine::SpecBuilder.new(JasmineHelper.raw_spec_files, jasmine_runner)
|
||||
|
||||
should_stop = false
|
||||
|
||||
Spec::Runner.configure do |config|
|
||||
config.after(:suite) do
|
||||
spec_builder.stop if should_stop
|
||||
end
|
||||
end
|
||||
|
||||
spec_builder.start
|
||||
should_stop = true
|
||||
spec_builder.declare_suites
|
65
spec/server_spec.rb
Normal file
65
spec/server_spec.rb
Normal file
@ -0,0 +1,65 @@
|
||||
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")
|
||||
})
|
||||
|
||||
config.stub!(:js_files).and_return(["/src/file1.js", "/spec/file2.js"])
|
||||
|
||||
@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
|
||||
|
||||
describe "/ page" do
|
||||
it "should load each js file in order" do
|
||||
code, headers, body = @thin_app.call("PATH_INFO" => "/", "SCRIPT_NAME" => "xxx")
|
||||
code.should == 200
|
||||
body = read(body)
|
||||
body.should include("\"/src/file1.js")
|
||||
body.should include("\"/spec/file2.js")
|
||||
body.should satisfy {|s| s.index("/src/file1.js") < s.index("/spec/file2.js") }
|
||||
end
|
||||
end
|
||||
|
||||
it "should display an error using JS for 404's" do
|
||||
code, headers, body = @thin_app.call("PATH_INFO" => "/spec/NonExistantFile.js", "SCRIPT_NAME" => "xxx")
|
||||
code.should == 200 # todo: shouldn't this be 404? will that work with all browsers?
|
||||
headers["Content-Type"].should == "application/javascript"
|
||||
read(body).should == "document.write('<p>Couldn\\'t load /spec/NonExistantFile.js!</p>');"
|
||||
end
|
||||
end
|
3
spec/spec_helper.rb
Normal file
3
spec/spec_helper.rb
Normal file
@ -0,0 +1,3 @@
|
||||
require 'spec'
|
||||
|
||||
require File.expand_path(File.join(File.dirname(__FILE__), "../lib/jasmine"))
|
@ -1,5 +1,5 @@
|
||||
namespace :jasmine do
|
||||
require 'jasmine-ruby'
|
||||
require 'jasmine'
|
||||
helper_overrides = File.expand_path(File.join(File.dirname(__FILE__), "spec/helpers/jasmine_helper.rb"))
|
||||
if File.exist?(helper_overrides)
|
||||
require helper_overrides
|
||||
@ -17,7 +17,7 @@ namespace :jasmine do
|
||||
puts "your tests are here:"
|
||||
puts " http://localhost:8888/run.html"
|
||||
|
||||
Jasmine::SimpleServer.start(8888,
|
||||
Jasmine::Server.start(8888,
|
||||
File.expand_path(Dir.pwd),
|
||||
lambda { JasmineHelper.specs },
|
||||
{ :spec_helpers => JasmineHelper.files + JasmineHelper.spec_helpers,
|
||||
|
2
templates/public/javascripts/example.js
Normal file
2
templates/public/javascripts/example.js
Normal file
@ -0,0 +1,2 @@
|
||||
ExampleClass = function() {
|
||||
};
|
@ -1,9 +1,9 @@
|
||||
describe('ExampleSuite', function () {
|
||||
describe('Example', function () {
|
||||
it('should have a passing test', function() {
|
||||
expect(true).toEqual(true);
|
||||
});
|
||||
|
||||
describe('Nested Describe', function () {
|
||||
describe('nested describe', function () {
|
||||
it('should also have a passing test', function () {
|
||||
expect(true).toEqual(true);
|
||||
});
|
Loading…
Reference in New Issue
Block a user