yet more hacking

This commit is contained in:
John Bintz 2012-03-13 13:21:32 -04:00
parent bbc95564f1
commit 0529359352
43 changed files with 763 additions and 204 deletions

View File

@ -5,9 +5,7 @@ require 'thor'
class Flowerbox::CLI < Thor class Flowerbox::CLI < Thor
desc "test DIR", "Run the specs found in spec dir, loading spec_helper.rb for configuration details" desc "test DIR", "Run the specs found in spec dir, loading spec_helper.rb for configuration details"
method_options :pwd => :string method_options :pwd => :string, :runners => :string, :verbose_server => false
method_options :runners => :string
method_options :verbose => false
def test(dir = "spec/javascripts") def test(dir = "spec/javascripts")
Dir.chdir(pwd) do Dir.chdir(pwd) do
exit Flowerbox.run(dir, options) exit Flowerbox.run(dir, options)

View File

@ -1,8 +1,35 @@
#= require_self
#= require flowerbox/result
#= require flowerbox/exception
#
Flowerbox = Flowerbox =
baseUrl: '/' baseUrl: '/'
ping: ->
Flowerbox.contact('ping')
pause: (time) ->
t = (new Date()).getTime()
while (t + time) > (new Date().getTime())
Flowerbox.ping()
contact: (url, data...) -> contact: (url, data...) ->
xhr = new XMLHttpRequest() attempts = 3
xhr.open("POST", Flowerbox.baseUrl + url, false)
xhr.setRequestHeader("Accept", "application/json") doContact = ->
xhr.send(JSON.stringify(data)) attempts -= 1
try
xhr = new XMLHttpRequest()
xhr.open("POST", Flowerbox.baseUrl + url, false)
xhr.setRequestHeader("Accept", "application/json")
xhr.send(JSON.stringify(data))
catch e
if attempts == 0
throw e
else
doContact()
doContact()
fail: -> fail: ->

View File

@ -6,25 +6,68 @@ Flowerbox.Cucumber.features = ->
Flowerbox.Cucumber.Features.join("\n") Flowerbox.Cucumber.Features.join("\n")
Flowerbox.World = (code = null) -> Flowerbox.World = (code = null) ->
-> if code
for code in (Flowerbox.World.Code || []) Flowerbox.World.Code ||= []
code.apply(this) Flowerbox.World.Code.push(code)
else
->
for code in (Flowerbox.World.Code || [])
code.apply(this)
Flowerbox.Matchers =
toEqual: (expected) ->
@message = "Expected #{@actual} #{@notMessage} equal #{expected}"
@actual == expected
Flowerbox.World ->
@assert = (what, message = 'failed') ->
throw new Error(message) if !what
@_pending = false
@pending = -> @_pending = true
@expect = (what) -> new Flowerbox.Matcher(what)
@addMatchers = (data) -> Flowerbox.Matcher.addMatchers(data)
Flowerbox.Matcher.matchers = {}
@addMatchers(Flowerbox.Matchers)
class Flowerbox.Matcher
@addMatchers: (data) ->
for method, code of data
Flowerbox.Matcher.matchers[method] = code
constructor: (@actual, @_negated = false) ->
@not = this.negated() if !@_negated
@notMessage = if @_negated then "to not" else "to"
generateMethod = (method) ->
(args...) -> @fail() if !@maybeNegate(Flowerbox.Matcher.matchers[method].apply(this, args))
for method, code of Flowerbox.Matcher.matchers
this[method] = generateMethod(method)
negated: ->
new Flowerbox.Matcher(@actual, true)
fail: ->
throw new Error(@message)
maybeNegate: (result) ->
result = !result if @_negated
result
Flowerbox.Step = (type, match, code) -> Flowerbox.Step = (type, match, code) ->
Flowerbox.World.Code ||= [] Flowerbox.World.Code ||= []
Flowerbox.World.Code.push (args..., callback) -> Flowerbox.World.Code.push (args..., callback) ->
this[type] match, (args..., callback) -> this[type] match, (args..., callback) =>
result = code.apply(this, args)
pending = false
this.pending = -> pending = true
result = code.apply(this)
if result? and result.__prototype__ == Error if result? and result.__prototype__ == Error
callback.fail(result) callback.fail(result)
else else
if pending then callback.pending("pending") else callback() if @_pending then callback.pending("pending") else callback()
null null
@ -41,13 +84,14 @@ stepGenerator = (type) ->
Flowerbox[type] = (match, code) -> Flowerbox[type] = (match, code) ->
if !Flowerbox.Step.files[match.toString()] if !Flowerbox.Step.files[match.toString()]
count = 2 count = 2
for line in (new Error()).stack.split('\n') if stack = (new Error()).stack
if line.match(/__F__/) for line in stack.split('\n')
count -= 1 if line.match(/__F__/)
count -= 1
if count == 0 if count == 0
Flowerbox.Step.files[match.toString()] = [ match, line.replace(/^.*__F__/, '') ] Flowerbox.Step.files[match.toString()] = [ match, line.replace(/^.*__F__/, '') ]
break break
Flowerbox.Step(type, match, code) Flowerbox.Step(type, match, code)

View File

@ -2,6 +2,19 @@ Flowerbox ||= {}
Flowerbox.Cucumber ||= {} Flowerbox.Cucumber ||= {}
class Flowerbox.Cucumber.Reporter class Flowerbox.Cucumber.Reporter
nameParts: ->
[ @feature.getName(), @scenario.getName(), "#{this.type()} #{@step.getName()}" ]
type: ->
type = "Given"
if @step.isOutcomeStep()
type = "Then"
else if @step.isEventStep()
type = "When"
type
hear: (event, callback) -> hear: (event, callback) ->
switch event.getName() switch event.getName()
when 'BeforeFeatures' when 'BeforeFeatures'
@ -26,40 +39,27 @@ class Flowerbox.Cucumber.Reporter
when 'StepResult' when 'StepResult'
stepResult = event.getPayloadItem('stepResult') stepResult = event.getPayloadItem('stepResult')
type = "Given"
if @step.isOutcomeStep()
type = "Then"
else if @step.isEventStep()
type = "When"
file = Flowerbox.Step.matchFile(@step.getName()) || "unknown:0" file = Flowerbox.Step.matchFile(@step.getName()) || "unknown:0"
test = { passed_: false, message: 'skipped', splitName: [ @feature.getName(), @scenario.getName(), "#{type} #{@step.getName()}" ], trace: { stack: [ file ] } } result = new Flowerbox.Result(step_type: this.type(), source: 'cucumber', original_name: @step.getName(), name: this.nameParts(), file: file)
if stepResult.isSuccessful() if stepResult.isSuccessful()
test.passed_ = true result.status = Flowerbox.Result.SUCCESS
else if stepResult.isPending() else if stepResult.isPending()
test.message = "pending" result.status = Flowerbox.Result.PENDING
else if stepResult.isUndefined() else if stepResult.isUndefined()
regexp = @step.getName() result.status = Flowerbox.Result.UNDEFINED
regexp = regexp.replace(/"[^"]+"/g, '"([^"]+)"')
test.message = """
Step not defined. Define it with the following:
Flowerbox.#{type} /^#{regexp}$/, ->
@pending()
"""
else if stepResult.isFailed() else if stepResult.isFailed()
result.status = Flowerbox.Result.FAILURE
error = stepResult.getFailureException() error = stepResult.getFailureException()
stack = (error.stack || "message\n#{file}:0").split("\n")
test.message = error.message failure = { runner: Flowerbox.environment, message: error.message, stack: stack }
test.trace.stack = [ 'file:1' ]
Flowerbox.contact("finish_test", @step.getName(), [ { items_: [ test ] } ]) result.failures.push(failure)
Flowerbox.contact("finish_test", result.toJSON())
callback() callback()

View File

@ -0,0 +1,4 @@
window.onerror = (message, file, line) ->
Flowerbox.contact("log", message)
Flowerbox.contact("log", " #{file}:#{line}")

View File

@ -0,0 +1,5 @@
class Flowerbox.Exception
constructor: (@stack) ->
toJSON: ->
{ trace: { stack: @stack } }

View File

@ -7,12 +7,21 @@ class jasmine.FlowerboxReporter
Flowerbox.contact("start_test", spec.description) Flowerbox.contact("start_test", spec.description)
if spec.description == 'encountered a declaration exception' if spec.description == 'encountered a declaration exception'
Flowerbox.contact("finish_test", spec.description, { trace: { stack: [ spec.description ] } }) Flowerbox.contact("finish_test", new Flowerbox.Exception([ spec.description ]))
Flowerbox.contact("results", 0) Flowerbox.contact("results", 0)
Flowerbox.fail() if Flowerbox.fail? Flowerbox.fail() if Flowerbox.fail?
reportSpecResults: (spec) -> reportSpecResults: (spec) ->
Flowerbox.contact("finish_test", spec.description, spec.results()) result = new Flowerbox.Result(status: Flowerbox.Result.SUCCESS, source: 'jasmine', name: spec.getSpecSplitName(), file: 'unknown:0')
for item in spec.results().items_
if !item.passed_
result.status = Flowerbox.Result.FAILURE
failure = { runner: Flowerbox.environment, message: item.message, stack: item.trace.stack }
result.failures.push(failure)
Flowerbox.contact("finish_test", result)
reportRunnerResults: (runner) -> reportRunnerResults: (runner) ->
Flowerbox.contact("results", (new Date().getTime()) - @time) Flowerbox.contact("results", (new Date().getTime()) - @time)

View File

@ -7,9 +7,9 @@ jasmine.Spec.beforeAddMatcherResult().push ->
if e.stack if e.stack
file = switch Flowerbox.environment file = switch Flowerbox.environment
when 'firefox' when 'firefox'
e.stack.split("\n")[3].replace(/^[^@]*@/, '') e.stack.split("\n")[3]
when 'chrome' when 'chrome'
e.stack.split("\n")[4].replace(/^.*\((.*)\)$/, '$1').replace(/:[^:]+$/, '') e.stack.split("\n")[4]
@trace = { stack: [ file.replace(/^.*__F__/, '') ] } @trace = { stack: [ file ] }

View File

@ -0,0 +1,17 @@
Flowerbox ||= {}
class Flowerbox.Result
@SUCCESS = 'success'
@PENDING = 'pending'
@UNDEFINED = 'undefined'
@FAILURE = 'failure'
@SKIPPED = 'skipped'
constructor: (data) ->
for key, value of data
this[key] = value
this.status ||= Flowerbox.Result.SKIPPED
this.failures ||= []
toJSON: => this

View File

@ -3,6 +3,10 @@ require 'flowerbox-delivery'
require 'rainbow' require 'rainbow'
module Flowerbox module Flowerbox
module CoreExt
autoload :Module, 'flowerbox/core_ext/module'
end
autoload :Runner, 'flowerbox/runner' autoload :Runner, 'flowerbox/runner'
module Runner module Runner
@ -26,12 +30,19 @@ module Flowerbox
autoload :ResultSet, 'flowerbox/result_set' autoload :ResultSet, 'flowerbox/result_set'
autoload :GatheredResult, 'flowerbox/gathered_result' autoload :GatheredResult, 'flowerbox/gathered_result'
autoload :Result, 'flowerbox/result' autoload :Result, 'flowerbox/result'
autoload :BaseResult, 'flowerbox/base_result'
autoload :Success, 'flowerbox/success' autoload :Reporter, 'flowerbox/reporter'
autoload :Failure, 'flowerbox/failure'
autoload :Exception, 'flowerbox/exception'
class << self class << self
attr_writer :reporters
def reset!
@spec_patterns = nil
@spec_files = nil
@asset_paths = nil
@reporters = nil
end
def spec_patterns def spec_patterns
@spec_patterns ||= [] @spec_patterns ||= []
end end
@ -40,6 +51,10 @@ module Flowerbox
@asset_paths ||= [] @asset_paths ||= []
end end
def reporters
@reporters ||= []
end
def test_with(what) def test_with(what)
self.test_environment = Flowerbox::TestEnvironment.for(what) self.test_environment = Flowerbox::TestEnvironment.for(what)
end end
@ -48,6 +63,10 @@ module Flowerbox
self.runner_environment = whats.flatten.collect { |what| Flowerbox::Runner.for(what.to_s) } self.runner_environment = whats.flatten.collect { |what| Flowerbox::Runner.for(what.to_s) }
end end
def report_with(*whats)
self.reporters = whats.flatten.collect { |what| Flowerbox::Reporter.for(what.to_s) }
end
def path def path
Pathname(File.expand_path('../..', __FILE__)) Pathname(File.expand_path('../..', __FILE__))
end end
@ -61,6 +80,10 @@ module Flowerbox
spec_patterns << "**/*_spec*" spec_patterns << "**/*_spec*"
spec_patterns << "*/*_spec*" spec_patterns << "*/*_spec*"
end end
if reporters.empty?
reporters << Flowerbox::Reporter.for(:progress)
end
end end
def bare_coffeescript def bare_coffeescript
@ -68,6 +91,8 @@ module Flowerbox
end end
def run(dir, options = {}) def run(dir, options = {})
reset!
load File.join(dir, 'spec_helper.rb') load File.join(dir, 'spec_helper.rb')
if options[:runners] if options[:runners]
@ -81,13 +106,18 @@ module Flowerbox
result_set = ResultSet.new result_set = ResultSet.new
time = 0
realtime = Time.now.to_i
Flowerbox.runner_environment.each do |env| Flowerbox.runner_environment.each do |env|
env.ensure_configured! env.ensure_configured!
result_set << env.run(build_sprockets_for(dir), spec_files_for(dir), options) result_set << env.run(build_sprockets_for(dir), spec_files_for(dir), options)
time += env.time
end end
result_set.print result_set.print(:time => time, :realtime => Time.now.to_i - realtime)
result_set.exitstatus result_set.exitstatus
end end
@ -116,7 +146,7 @@ module Flowerbox
Flowerbox.spec_patterns.each do |pattern| Flowerbox.spec_patterns.each do |pattern|
Dir[File.join(dir, pattern)].each do |file| Dir[File.join(dir, pattern)].each do |file|
@spec_files << file.gsub(dir + '/', '') @spec_files << File.expand_path(file)
end end
end end

View File

@ -1,18 +0,0 @@
module Flowerbox
class BaseResult < Result
attr_reader :name, :message, :file
def initialize(name, message, file = nil)
@name, @message, @file = name, message, file
end
def ==(other)
@name == other.name && @message == other.message
end
def to_s
"#{message} [#{runners.join(',')}] (#{translated_file}:#{line_number})"
end
end
end

View File

@ -0,0 +1,14 @@
module Flowerbox
module CoreExt
module Module
def find_constant(string)
const_get(constants.find { |f| f.to_s.downcase == string.to_s.downcase })
end
def for(env)
find_constant(env).new
end
end
end
end

View File

@ -1,15 +0,0 @@
module Flowerbox
class Exception < Result
attr_reader :name
def initialize(name)
@name = name
end
def print
puts "[#{runners.join(',')}] #{name}"
puts
end
end
end

View File

@ -25,16 +25,6 @@ module Flowerbox
def success? def success?
@results.all?(&:success?) @results.all?(&:success?)
end end
def print
puts name.join(' ')
results.each do |result|
puts " #{result}"
end
puts
end
end end
end end

View File

@ -33,13 +33,17 @@ module Flowerbox
end end
empty_post '/finish_test' do empty_post '/finish_test' do
runner.add_results(data.flatten[1..-1]) runner.add_results(data.flatten)
end end
empty_post '/log' do empty_post '/log' do
runner.log(data.first) runner.log(data.first)
end end
empty_post '/ping' do
runner.ping
end
get %r{^/__F__(/.*)$} do |file| get %r{^/__F__(/.*)$} do |file|
File.read(file) File.read(file)
end end

12
lib/flowerbox/reporter.rb Normal file
View File

@ -0,0 +1,12 @@
module Flowerbox
module Reporter
extend Flowerbox::CoreExt::Module
autoload :Base, 'flowerbox/reporter/base'
autoload :ConsoleBase, 'flowerbox/reporter/console_base'
autoload :Verbose, 'flowerbox/reporter/verbose'
autoload :Progress, 'flowerbox/reporter/progress'
autoload :FileDisplay, 'flowerbox/reporter/file_display'
end
end

View File

@ -0,0 +1,45 @@
module Flowerbox::Reporter
class Base
def post_report_data
@post_report_data ||= {}
end
def report(gathered_results, data = {})
gathered_results.each do |result|
self.send("report_#{result.type}", result)
end
report_numeric_results(gathered_results, data)
post_report_data.each do |type, data|
puts
self.send("post_report_#{type}", data)
end
end
def post_report_success(data) ; end
def post_report_skipped(data) ; end
def post_report_pending(data) ; end
def post_report_undefined(data)
puts "Some steps were not defined. Define them using the following code:".foreground(:yellow)
puts
data.each do |code|
puts code.foreground(:yellow)
end
end
def post_report_failed(data) ; end
protected
def numeric_results_for(gathered_results)
{
:total => gathered_results.length,
:failures => gathered_results.find_all(&:failure?).length,
:pending => gathered_results.find_all(&:pending?).length
}
end
end
end

View File

@ -0,0 +1,41 @@
module Flowerbox::Reporter
class ConsoleBase < Base
include FileDisplay
def report_success(result) ; end
def report_skipped(result) ; end
def report_pending(result)
puts
puts result.name.join(" - ").foreground(:yellow)
puts " Pending (finish defining the test)".foreground(:yellow) + ' ' + path_for(result)
end
def report_undefined(result)
(post_report_data[:undefined] ||= []) << result.test_environment.obtain_test_definition_for(result)
end
def report_failure(result)
puts
puts result.name.join(" - ").foreground(:red)
result.failures.each do |failure|
puts " " + failure.message.foreground(:red) + " [" + failure.runners.join(',') + "] " + path_for(failure)
end
end
def report_numeric_results(gathered_results, data = {})
results = numeric_results_for(gathered_results)
output = "#{results[:total]} total, #{results[:failures]} failed, #{results[:pending]} pending, #{data[:time].to_f / 1000} (#{data[:realtime]}.0) secs."
color = :green
color = :yellow if results[:pending] > 0
color = :red if results[:failures] > 0
puts
puts output.foreground(color)
puts
end
end
end

View File

@ -0,0 +1,13 @@
module Flowerbox::Reporter
module FileDisplay
private
def path_for(result)
if result.line.gsub(%r{[^0-9]}, '').to_i == 0
''
else
result.translated_file_and_line.foreground(:cyan)
end
end
end
end

View File

@ -0,0 +1,29 @@
module Flowerbox::Reporter
class Progress < ConsoleBase
def report_progress(result)
print self.send("progress_#{result.type}")
$stdout.flush
end
def progress_skipped
"-".foreground(:blue)
end
def progress_success
".".foreground(:green)
end
def progress_failure
"F".foreground(:red)
end
def progress_pending
"P".foreground(:yellow)
end
def progress_undefined
"U".foreground(:yellow)
end
end
end

View File

@ -0,0 +1,51 @@
module Flowerbox::Reporter
class Verbose < ConsoleBase
def initialize
@name_stack = []
end
def indent(text, count)
" " * count + text
end
def report_progress(result)
result.name.each_with_index do |name, index|
if @name_stack[index] != name
if name != result.name.last
message = name
else
message = self.send("progress_#{result.type}", result)
if !(file_display = path_for(result)).empty?
message << " # #{file_display}"
end
end
puts indent(message, index)
end
end
@name_stack = result.name.dup
end
def progress_skipped(result)
result.name.last.foreground(:blue)
end
def progress_success(result)
result.name.last.foreground(:green)
end
def progress_failure(result)
result.name.last.foreground(:red)
end
def progress_pending(result)
"#{result.name.last} (Pending)".foreground(:yellow)
end
def progress_undefined(result)
"#{result.name.last} (Undefined)".foreground(:yellow)
end
end
end

View File

@ -1,45 +1,28 @@
module Flowerbox module Flowerbox
class Result module Result
def <=>(other) extend Flowerbox::CoreExt::Module
result = self.name.length <=> other.name.length
if result == 0 module Cucumber
extend Flowerbox::CoreExt::Module
end
module Jasmine
extend Flowerbox::CoreExt::Module
end
autoload :Base, 'flowerbox/result/base'
autoload :Failure, 'flowerbox/result/failure'
autoload :Pending, 'flowerbox/result/pending'
autoload :FailureMessage, 'flowerbox/result/failure_message'
autoload :FileInfo, 'flowerbox/result/file_info'
class << self
def for(test_env, type)
require "flowerbox/result/#{test_env}/#{type}"
test_group = find_constant(test_env)
test_group.find_constant(type)
end end
result
end
def runners
@runners ||= []
end
def translated_file
@translated_file ||= if actual_file_base = filename[%r{\.tmp/sprockets(.*)}, 1]
Dir[actual_file_base + "*"].first
else
filename
end
end
def file_translated?
translated_file != filename
end
def filename
file.to_s.split(":").first
end
def line_number
return @line_number if @line_number
@line_number = file.to_s.split(":").last
@line_number = "~#{@line_number}" if file_translated?
@line_number
end
def success?
false
end end
end end
end end

View File

@ -0,0 +1,79 @@
require 'forwardable'
module Flowerbox
module Result
class Base
include Flowerbox::Result::FileInfo
extend Forwardable
attr_reader :data
def_delegators :data, :[]
def type
self.class.name.split("::").last.downcase.to_sym
end
def initialize(data)
@data = data
end
def name
data['name']
end
def message
data['message']
end
def runners
data['runners']
end
def file
data['file']
end
def ==(other)
name == other.name
end
def <=>(other)
result = self.name.length <=> other.name.length
if result == 0
end
result
end
def runners
@runners ||= []
end
def success?
false
end
def failure?
!success?
end
def pending?
false
end
def <<(other)
runners
@runners += other.runners
end
def test_environment
Flowerbox.test_environment
end
end
end
end

View File

View File

@ -0,0 +1,7 @@
module Flowerbox::Result
module Cucumber
class Failure < Flowerbox::Result::Failure
end
end
end

View File

@ -0,0 +1,8 @@
module Flowerbox::Result
module Cucumber
class Pending < Flowerbox::Result::Pending
end
end
end

View File

@ -0,0 +1,7 @@
module Flowerbox::Result
module Cucumber
class Skipped < Flowerbox::Result::Pending
end
end
end

View File

@ -0,0 +1,10 @@
module Flowerbox::Result
module Cucumber
class Success < Flowerbox::Result::Base
def success?
true
end
end
end
end

View File

@ -0,0 +1,14 @@
module Flowerbox::Result
module Cucumber
class Undefined < Flowerbox::Result::Pending
def step_type
@data['step_type']
end
def original_name
@data['original_name']
end
end
end
end

View File

@ -0,0 +1,6 @@
module Flowerbox::Result
class Exception < Base
end
end

View File

@ -0,0 +1,20 @@
module Flowerbox::Result
class Failure < Flowerbox::Result::Base
def failures
@failures ||= @data['failures'].collect { |fail| FailureMessage.new(fail) }
end
def <<(other)
super
other.failures.each do |failure|
if existing_failure = failures.find { |f| f.message == failure.message }
existing_failure.runners << failure.runner
else
failures << failure
end
end
end
end
end

View File

@ -0,0 +1,32 @@
module Flowerbox::Result
class FailureMessage
include Flowerbox::Result::FileInfo
attr_reader :data
def initialize(data)
@data = data
end
def message
@data['message']
end
def file
first_local_stack[%r{(#{Dir.pwd}.*$)}, 1]
end
def runner
@data['runner']
end
def runners
@runners ||= [ runner ]
end
def first_local_stack
@data['stack'].find { |line| line[File.join(".tmp/sprockets", Dir.pwd)] } || @data['stack'][1]
end
end
end

View File

@ -0,0 +1,32 @@
module Flowerbox::Result::FileInfo
def translated_file
@translated_file ||= if actual_file_base = filename[%r{\.tmp/sprockets(.*)}, 1]
Dir[actual_file_base + "*"].first
else
filename
end
end
def file_translated?
translated_file != filename
end
def filename
file.to_s.split(":").first
end
def line_number
return @line_number if @line_number
@line_number = file.to_s.split(":")[1]
@line_number = "~#{@line_number}" if file_translated?
@line_number
end
alias :line :line_number
def translated_file_and_line
"#{translated_file.gsub(Dir.pwd + '/', '')}:#{line_number}"
end
end

View File

@ -0,0 +1,7 @@
module Flowerbox::Result
module Jasmine
class Failure < Flowerbox::Result::Failure
end
end
end

View File

@ -0,0 +1,8 @@
module Flowerbox::Result
module Jasmine
class Success < Flowerbox::Result::Base
def success? ; true ; end
end
end
end

View File

@ -0,0 +1,12 @@
module Flowerbox::Result
class Pending < Base
def pending?
true
end
def failure?
false
end
end
end

View File

@ -5,21 +5,16 @@ module Flowerbox
attr_accessor :time attr_accessor :time
def self.from_results(results, options) def self.from_results(results, options)
results = results['items_'].collect do |result| results = results.collect do |result|
if name = result['splitName'] result['runner'] = options[:runner]
case result['passed_']
when true if name = result['name']
Success.new(name, result['message']) Flowerbox::Result.for(result['source'], result['status']).new(result)
else
Failure.new(name, result['message'], result['trace']['stack'].first)
end
else else
Exception.new(result.first['trace']['stack']) Flowerbox::Result::Exception.new(result)
end end
end.flatten end.flatten
results.each { |result| result.runners << options[:runner] }
new(results, options) new(results, options)
end end
@ -27,6 +22,10 @@ module Flowerbox
new(results, :runner => runner) new(results, :runner => runner)
end end
def reporters
Flowerbox.reporters
end
def initialize(results = [], options = {}) def initialize(results = [], options = {})
@results, @options = results, options @results, @options = results, options
end end
@ -34,7 +33,7 @@ module Flowerbox
def <<(other) def <<(other)
other.results.each do |other_result| other.results.each do |other_result|
if existing_result = results.find { |result| result == other_result } if existing_result = results.find { |result| result == other_result }
existing_result.runners << other_result.runners existing_result << other_result
else else
results << other_result results << other_result
end end
@ -45,10 +44,8 @@ module Flowerbox
@results.empty? ? 0 : 1 @results.empty? ? 0 : 1
end end
def print def print(data = {})
gathered_results.each(&:print) reporters.each { |reporter| reporter.report(flattened_gathered_results, data) }
puts "#{total_tests} total, #{total_failures} failures, #{time} secs."
end end
def total_tests def total_tests
@ -60,7 +57,9 @@ module Flowerbox
end end
def print_progress def print_progress
@results.each { |result| result.print_progress ; $stdout.flush } @results.each do |result|
reporters.each { |reporter| reporter.report_progress(result) }
end
end end
def gathered_results def gathered_results
@ -69,22 +68,21 @@ module Flowerbox
@gathered_results = [] @gathered_results = []
results.each do |result| results.each do |result|
case result if !(gathered_result = @gathered_results.find { |g| g.name == result.name })
when Flowerbox::Exception gathered_result = GatheredResult.new(result.name)
@gathered_results << result
when Flowerbox::Failure
if !(gathered_result = @gathered_results.find { |g| g.name == result.name })
gathered_result = GatheredResult.new(result.name)
@gathered_results << gathered_result @gathered_results << gathered_result
end
gathered_result << result
end end
gathered_result << result
end end
@gathered_results @gathered_results
end end
def flattened_gathered_results
gathered_results.collect(&:results).flatten
end
end end
end end

View File

@ -1,10 +1,6 @@
module Flowerbox module Flowerbox
module Runner module Runner
class << self extend Flowerbox::CoreExt::Module
def for(env)
self.const_get(self.constants.find { |c| c.to_s.downcase.to_s == env.to_s }).new
end
end
end end
end end

View File

@ -1,17 +1,28 @@
module Flowerbox module Flowerbox
module Runner module Runner
class Base class Base
attr_reader :sprockets, :spec_files, :options attr_reader :sprockets, :spec_files, :options, :time
attr_accessor :results attr_accessor :results
MAX_COUNT = 30
def initialize def initialize
@results = ResultSet.new @results = ResultSet.new
end end
def ensure_alive
while @count < MAX_COUNT && !finished?
@count += 1
sleep 0.1
end
end
def run(sprockets, spec_files, options) def run(sprockets, spec_files, options)
@sprockets, @spec_files, @options = sprockets, spec_files, options @sprockets, @spec_files, @options = sprockets, spec_files, options
@count = 0
puts "Flowerbox running your #{Flowerbox.test_environment.name} tests on #{console_name}..." puts "Flowerbox running your #{Flowerbox.test_environment.name} tests on #{console_name}..."
server.start server.start
@ -20,9 +31,6 @@ module Flowerbox
server.stop server.stop
puts
puts
@results @results
end end
@ -56,7 +64,7 @@ module Flowerbox
return @server if @server return @server if @server
server_options = { :app => Flowerbox::Rack } server_options = { :app => Flowerbox::Rack }
server_options[:logging] = true if options[:verbose] server_options[:logging] = true if options[:verbose_server]
@server = Flowerbox::Delivery::Server.new(server_options) @server = Flowerbox::Delivery::Server.new(server_options)
Flowerbox::Rack.runner = self Flowerbox::Rack.runner = self
@ -74,6 +82,8 @@ module Flowerbox
def add_tests(new_tests) def add_tests(new_tests)
tests << new_tests tests << new_tests
@count = 0
end end
def failures def failures
@ -96,6 +106,10 @@ module Flowerbox
@failures.length @failures.length
end end
def time
@time ||= 0
end
def finish!(time) def finish!(time)
@time = time @time = time
@ -106,9 +120,13 @@ module Flowerbox
@finished @finished
end end
def ping
@count = 0
end
private private
def result_set_from_test_results(test_results) def result_set_from_test_results(test_results)
ResultSet.from_results(test_results.first, options.merge(:runner => name)) ResultSet.from_results(test_results, options.merge(:runner => name))
end end
end end
end end

View File

@ -3,7 +3,6 @@ require 'selenium-webdriver'
module Flowerbox module Flowerbox
module Runner module Runner
class Selenium < Base class Selenium < Base
MAX_COUNT = 30
def name def name
raise StandardError.new("Override me") raise StandardError.new("Override me")
@ -20,12 +19,7 @@ module Flowerbox
selenium.navigate.to "http://localhost:#{server.port}/" selenium.navigate.to "http://localhost:#{server.port}/"
@count = 0 ensure_alive
while @count < MAX_COUNT && !finished?
@count += 1
sleep 0.1
end
ensure ensure
selenium.quit if selenium selenium.quit if selenium
end end
@ -60,7 +54,9 @@ console.log = function(msg) {
var context = this; var context = this;
#{env} window.onload = function() {
#{env}
};
</script> </script>
</body> </body>
</html> </html>
@ -70,12 +66,6 @@ HTML
def template_files def template_files
sprockets.files.collect { |file| %{<script type="text/javascript" src="/__F__#{file}"></script>} } sprockets.files.collect { |file| %{<script type="text/javascript" src="/__F__#{file}"></script>} }
end end
def add_failures(data)
super
@count = 0
end
end end
end end
end end

View File

@ -1,8 +1,10 @@
module Flowerbox module Flowerbox
module TestEnvironment module TestEnvironment
extend Flowerbox::CoreExt::Module
class << self class << self
def for(env) def for(env)
self.const_get(self.constants.find { |c| c.to_s.downcase.to_s == env.to_s }).new find_constant(env).new
end end
end end
end end

View File

@ -10,10 +10,12 @@ module Flowerbox
end end
def start_for(runner) def start_for(runner)
@runner = runner
@sprockets.add("flowerbox/cucumber") @sprockets.add("flowerbox/cucumber")
@sprockets.add("flowerbox/cucumber/#{runner.type}") @sprockets.add("flowerbox/cucumber/#{runner.type}")
runner.spec_files.each { |file| @sprockets.add(file) } @runner.spec_files.each { |file| @sprockets.add(file) }
<<-JS <<-JS
context.Cucumber = context.require('./cucumber'); context.Cucumber = context.require('./cucumber');
@ -23,6 +25,43 @@ context.cucumber.attachListener(new context.Flowerbox.Cucumber.Reporter());
context.cucumber.start(function() {}); context.cucumber.start(function() {});
JS JS
end end
def obtain_test_definition_for(result)
matcher = result.original_name
args = []
matcher.gsub!(%r{"[^"]+"}) do |_, match|
args << "arg#{args.length + 1}"
'"([^"]+)"'
end
matcher.gsub!(%r{ \d+ }) do |_, match|
args << "arg#{args.length + 1}"
" (\d+) "
end
args_string = args.join(', ')
if primarily_coffeescript?
<<-COFFEE
Flowerbox.#{result.step_type} /^#{matcher}$/, #{"(#{args_string}) " if !args_string.empty?}->
@pending() # add your code here
COFFEE
else
<<-JS
Flowerbox.#{result.step_type}(/^#{matcher}$/, function(#{args_string}) {
this.pending(); // add your code here
});
JS
end
end
def primarily_coffeescript?
coffee_count = @runner.spec_files.inject(0) { |s, n| s += 1 if n[%r{.coffee$}]; s }
js_count = @runner.spec_files.inject(0) { |s, n| s += 1 if n[%r{.js$}]; s }
coffee_count > js_count
end
end end
end end
end end

View File

@ -25,18 +25,9 @@ if (typeof context != 'undefined' && typeof jasmine == 'undefined') {
} }
jasmine.getEnv().addReporter(new jasmine.FlowerboxReporter()); jasmine.getEnv().addReporter(new jasmine.FlowerboxReporter());
#{jasmine_reporters.join("\n")}
jasmine.getEnv().execute(); jasmine.getEnv().execute();
JS JS
end end
def jasmine_reporters
reporters.collect { |reporter| %{jasmine.getEnv().addReporter(new jasmine.#{reporter}());} }
end
def reporters
@reporters ||= []
end
end end
end end
end end