diff --git a/contrib/ruby/jasmine_runner.rb b/contrib/ruby/jasmine_runner.rb deleted file mode 100644 index 2388396..0000000 --- a/contrib/ruby/jasmine_runner.rb +++ /dev/null @@ -1,334 +0,0 @@ -require 'socket' -require 'erb' -require 'json' - -module Jasmine - def self.root - File.expand_path(File.join(File.dirname(__FILE__), '../..')) - 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('

Couldn\\'t load #{env["PATH_INFO"]}!

');" - ] - 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('

Couldn\\'t find any specs matching #{env["PATH_INFO"]}!

');" - ] - end - end - - end - - class SimpleServer - def self.start(port, spec_files_or_proc, mappings, 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) - } - 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(selenium_jar_path, spec_files, dir_mappings, options={}) - @selenium_jar_path = selenium_jar_path - @spec_files = spec_files - @dir_mappings = dir_mappings - @options = options - - @browser = options[:browser] ? options[:browser].delete(:browser) : 'firefox' - @selenium_pid = nil - @jasmine_server_pid = nil - @selenium_host = 'localhost' - @jasmine_server_port = Jasmine::find_unused_port - @selenium_server_port = Jasmine::find_unused_port - end - - def start - start_jasmine_server - start_selenium_server - @client = Jasmine::SimpleClient.new(@selenium_host, @selenium_server_port, "*#{@browser}", "http://localhost:#{@jasmine_server_port}/") - @client.connect - end - - def stop - @client.disconnect - stop_selenium_server - stop_jasmine_server - end - - def start_jasmine_server - @jasmine_server_pid = fork do - Process.setpgrp - Jasmine::SimpleServer.start(@jasmine_server_port, @spec_files, @dir_mappings, @options) - exit! 0 - end - puts "jasmine server started. pid is #{@jasmine_server_pid}" - Jasmine::wait_for_listener(@jasmine_server_port, "jasmine server") - end - - def start_selenium_server - @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::wait_for_listener(@selenium_server_port, "selenium server") - end - - def stop_jasmine_server - puts "shutting down Jasmine server..." - Jasmine::kill_process_group(@jasmine_server_pid) if @jasmine_server_pid - end - - def stop_selenium_server - puts "shutting down Selenium server..." - Jasmine::kill_process_group(@selenium_pid) if @selenium_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 - - class SauceLabsRunner < Runner - def initialize(spec_files, dir_mappings, options={}) - @spec_files = spec_files - @dir_mappings = dir_mappings - @options = options - - @browser = options[:browser] ? options[:browser].delete(:browser) : 'firefox' - @jasmine_server_pid = nil - @jasmine_server_port = Jasmine::find_unused_port - @saucelabs_config = SeleniumConfig.new(options[:saucelabs_config], options[:saucelabs_config_file], @jasmine_server_port) - end - - def start_selenium_server - @sauce_tunnel = SauceTunnel.new(@saucelabs_config) - end - - def start - start_jasmine_server - start_selenium_server - @client = Jasmine::SimpleClient.new(@saucelabs_config['selenium_server_address'], - 4444, - @saucelabs_config['selenium_browser_key'], - "http://#{@saucelabs_config['application_address']}") - @client.connect - end - - def stop - @client.disconnect - @sauce_tunnel.shutdown - stop_jasmine_server - end - - end - - def self.files(f) - result = f - result = result.call if result.respond_to?(:call) - result - end - -end diff --git a/contrib/ruby/jasmine_spec_builder.rb b/contrib/ruby/jasmine_spec_builder.rb deleted file mode 100644 index 260c9e2..0000000 --- a/contrib/ruby/jasmine_spec_builder.rb +++ /dev/null @@ -1,153 +0,0 @@ -require File.expand_path(File.join(File.dirname(__FILE__), "jasmine_runner.rb")) -require 'enumerator' -module Jasmine - - class SpecBuilder - attr_accessor :suites - - def initialize(spec_files, runner) - @spec_files = spec_files - @runner = runner - @spec_ids = [] - end - - def start - guess_example_locations - - @runner.start - load_suite_info - wait_for_suites_to_finish_running - end - - def stop - @runner.stop - end - - def script_path - File.expand_path(__FILE__) - end - - def guess_example_locations - @example_locations = {} - - example_name_parts = [] - previous_indent_level = 0 - @spec_files.each do |filename| - line_number = 1 - File.open(filename, "r") do |file| - file.readlines.each do |line| - match = /^(\s*)(describe|it)\s*\(\s*["'](.*)["']\s*,\s*function/.match(line) - if (match) - indent_level = match[1].length / 2 - example_name = match[3] - example_name_parts[indent_level] = example_name - - full_example_name = example_name_parts.slice(0, indent_level + 1).join(" ") - @example_locations[full_example_name] = "#{filename}:#{line_number}: in `it'" - end - line_number += 1 - end - end - end - end - - def load_suite_info - started = Time.now - while !eval_js('jsApiReporter && jsApiReporter.started') do - raise "couldn't connect to Jasmine after 60 seconds" if (started + 60 < Time.now) - sleep 0.1 - end - - @suites = eval_js('JSON.stringify(jsApiReporter.suites())') - end - - def results_for(spec_id) - @spec_results ||= load_results - @spec_results[spec_id.to_s] - end - - def load_results - @spec_results = {} - @spec_ids.each_slice(50) do |slice| - @spec_results.merge!(eval_js("JSON.stringify(jsApiReporter.resultsForSpecs(#{JSON.generate(slice)}))")) - end - @spec_results - end - - def wait_for_suites_to_finish_running - puts "Waiting for suite to finish in browser ..." - while !eval_js('jsApiReporter.finished') do - sleep 0.1 - end - end - - def declare_suites - me = self - suites.each do |suite| - declare_suite(self, suite) - end - end - - def declare_suite(parent, suite) - me = self - parent.describe suite["name"] do - suite["children"].each do |suite_or_spec| - type = suite_or_spec["type"] - if type == "suite" - me.declare_suite(self, suite_or_spec) - elsif type == "spec" - me.declare_spec(self, suite_or_spec) - else - raise "unknown type #{type} for #{suite_or_spec.inspect}" - end - end - end - end - - def declare_spec(parent, spec) - me = self - example_name = spec["name"] - @spec_ids << spec["id"] - backtrace = @example_locations[parent.description + " " + example_name] - parent.it example_name, {}, backtrace do - me.report_spec(spec["id"]) - end - end - - def report_spec(spec_id) - spec_results = results_for(spec_id) - - out = "" - messages = spec_results['messages'].each do |message| - case - when message["type"] == "MessageResult" - puts message["text"] - puts "\n" - else - unless message["message"] =~ /^Passed.$/ - STDERR << message["message"] - STDERR << "\n" - - out << message["message"] - out << "\n" - end - - if !message["passed"] && message["trace"]["stack"] - stack_trace = message["trace"]["stack"].gsub(/
/, "\n").gsub(/<\/?b>/, " ") - STDERR << stack_trace.gsub(/\(.*\)@http:\/\/localhost:[0-9]+\/specs\//, "/spec/") - STDERR << "\n" - end - end - - end - fail out unless spec_results['result'] == 'passed' - puts out unless out.empty? - end - - private - - def eval_js(js) - @runner.eval_js(js) - end - end -end diff --git a/contrib/ruby/run.html b/contrib/ruby/run.html deleted file mode 100644 index 9f0ecd0..0000000 --- a/contrib/ruby/run.html +++ /dev/null @@ -1,47 +0,0 @@ - - - - - Jasmine suite - <% css_files.each do |css_file| %> - - <% end %> - - <% jasmine_files.each do |jasmine_file| %> - - <% end %> - - <% spec_helpers.each do |spec_helper| %> - - <% end %> - - - - <% spec_files.each do |spec_file| %> - - <% end %> - - - -
- - diff --git a/contrib/ruby/spec/jasmine_runner_spec.rb b/contrib/ruby/spec/jasmine_runner_spec.rb deleted file mode 100644 index 054f3dd..0000000 --- a/contrib/ruby/spec/jasmine_runner_spec.rb +++ /dev/null @@ -1,71 +0,0 @@ -require 'spec' -require 'open-uri' -require 'thin' - -require File.dirname(__FILE__) + '/../jasmine_runner' - -describe Jasmine::SimpleServer do - before do - @port = Jasmine::find_unused_port - end - - after do - Jasmine::kill_process_group(@jasmine_server_pid) if @jasmine_server_pid - end - - it "should start and print script tags" do - @jasmine_server_pid = fork do - Process.setpgrp - Jasmine::SimpleServer.start(@port, ["file1", "file2"], {}) - exit! 0 - end - - Jasmine::wait_for_listener(@port) - - run_html = open("http://localhost:#{@port}/").read - run_html.should =~ /