module Jasmine module Runners class HTTP attr_accessor :suites def initialize(client, results_processor, result_batch_size) @client = client @results_processor = results_processor @result_batch_size = result_batch_size end def run @client.connect load_suite_info wait_for_suites_to_finish_running results = @results_processor.process(results_hash, suites) @client.disconnect results end private def load_suite_info started = Time.now while !eval_js('return 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("var result = jsApiReporter.suites(); if (window.Prototype && Object.toJSON) { return Object.toJSON(result) } else { return JSON.stringify(result) }") @total_spec_count = eval_js("return jasmine.getEnv().currentRunner().specs().length;") end def results_hash spec_results = {} spec_ids.each_slice(@result_batch_size) do |slice| spec_results.merge!(eval_js("var result = jsApiReporter.resultsForSpecs(#{json_generate(slice)}); if (window.Prototype && Object.toJSON) { return Object.toJSON(result) } else { return JSON.stringify(result) }")) end spec_results end def spec_ids map_spec_ids = lambda do |suites| suites.map do |suite_or_spec| if suite_or_spec['type'] == 'spec' suite_or_spec['id'] else map_spec_ids.call(suite_or_spec['children']) end end end map_spec_ids.call(@suites).compact.flatten end def wait_for_suites_to_finish_running $stderr.puts "Waiting for suite to finish in browser (#{@total_spec_count} specs)..." @spec_status = '' @finished_spec_count = 0 @output_spec_count = 0 while !eval_js('return jsApiReporter.finished') do return if @unresponsive_script_detected sleep 2 status = eval_js('return jsApiReporter.getLatestStatus()') output_status(status) end status = eval_js('return jsApiReporter.getLatestStatus()') output_status(status, true) duration = eval_js('return jsApiReporter.getDurationForRun()') $stderr.puts "\nSuites took #{duration/1000} seconds\n" end def output_status(chunk, flush = false) return unless chunk status_count = chunk['count'] failures = chunk['failures'] status = chunk['results'] @finished_spec_count += status_count @spec_status += status while @spec_status.size >= 100 @output_spec_count += 100 $stderr.puts @spec_status[0...100] + finished_of_total_count @spec_status = @spec_status[100..-1] end if flush && @spec_status.size > 0 @output_spec_count = @finished_spec_count $stderr.puts @spec_status + finished_of_total_count @spec_status = '' end failures.each { |f| $stderr.puts f } end def finished_of_total_count " (#{@output_spec_count} of #{@total_spec_count})" end def eval_js(script) begin return @client.eval_js(script) rescue Selenium::WebDriver::Error::UnhandledAlertError => e handle_unexpected_alert e end end def handle_unexpected_alert(e) alert_text = @client.get_alert_text @client.close_alert $stderr.puts <<-ALERT_MSG Unexpected alert: "#{alert_text}" #{e.message} happened near: #{@client.eval_js('return jsApiReporter.getLatestSpecToHaveFinished()')} ALERT_MSG @unresponsive_script_detected = e.message =~ /stopped responding/ return nil end def json_generate(obj) @client.json_generate(obj) end end end end