yet more hacking
This commit is contained in:
parent
bbc95564f1
commit
0529359352
@ -5,9 +5,7 @@ require 'thor'
|
||||
|
||||
class Flowerbox::CLI < Thor
|
||||
desc "test DIR", "Run the specs found in spec dir, loading spec_helper.rb for configuration details"
|
||||
method_options :pwd => :string
|
||||
method_options :runners => :string
|
||||
method_options :verbose => false
|
||||
method_options :pwd => :string, :runners => :string, :verbose_server => false
|
||||
def test(dir = "spec/javascripts")
|
||||
Dir.chdir(pwd) do
|
||||
exit Flowerbox.run(dir, options)
|
||||
|
@ -1,8 +1,35 @@
|
||||
#= require_self
|
||||
#= require flowerbox/result
|
||||
#= require flowerbox/exception
|
||||
#
|
||||
Flowerbox =
|
||||
baseUrl: '/'
|
||||
ping: ->
|
||||
Flowerbox.contact('ping')
|
||||
|
||||
pause: (time) ->
|
||||
t = (new Date()).getTime()
|
||||
|
||||
while (t + time) > (new Date().getTime())
|
||||
Flowerbox.ping()
|
||||
|
||||
contact: (url, data...) ->
|
||||
xhr = new XMLHttpRequest()
|
||||
xhr.open("POST", Flowerbox.baseUrl + url, false)
|
||||
xhr.setRequestHeader("Accept", "application/json")
|
||||
xhr.send(JSON.stringify(data))
|
||||
attempts = 3
|
||||
|
||||
doContact = ->
|
||||
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: ->
|
||||
|
||||
|
@ -6,25 +6,68 @@ Flowerbox.Cucumber.features = ->
|
||||
Flowerbox.Cucumber.Features.join("\n")
|
||||
|
||||
Flowerbox.World = (code = null) ->
|
||||
->
|
||||
for code in (Flowerbox.World.Code || [])
|
||||
code.apply(this)
|
||||
if code
|
||||
Flowerbox.World.Code ||= []
|
||||
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.World.Code ||= []
|
||||
Flowerbox.World.Code.push (args..., callback) ->
|
||||
this[type] match, (args..., callback) ->
|
||||
|
||||
pending = false
|
||||
|
||||
this.pending = -> pending = true
|
||||
|
||||
result = code.apply(this)
|
||||
this[type] match, (args..., callback) =>
|
||||
result = code.apply(this, args)
|
||||
|
||||
if result? and result.__prototype__ == Error
|
||||
callback.fail(result)
|
||||
else
|
||||
if pending then callback.pending("pending") else callback()
|
||||
if @_pending then callback.pending("pending") else callback()
|
||||
|
||||
null
|
||||
|
||||
@ -41,13 +84,14 @@ stepGenerator = (type) ->
|
||||
Flowerbox[type] = (match, code) ->
|
||||
if !Flowerbox.Step.files[match.toString()]
|
||||
count = 2
|
||||
for line in (new Error()).stack.split('\n')
|
||||
if line.match(/__F__/)
|
||||
count -= 1
|
||||
if stack = (new Error()).stack
|
||||
for line in stack.split('\n')
|
||||
if line.match(/__F__/)
|
||||
count -= 1
|
||||
|
||||
if count == 0
|
||||
Flowerbox.Step.files[match.toString()] = [ match, line.replace(/^.*__F__/, '') ]
|
||||
break
|
||||
if count == 0
|
||||
Flowerbox.Step.files[match.toString()] = [ match, line.replace(/^.*__F__/, '') ]
|
||||
break
|
||||
|
||||
Flowerbox.Step(type, match, code)
|
||||
|
||||
|
@ -2,6 +2,19 @@ Flowerbox ||= {}
|
||||
Flowerbox.Cucumber ||= {}
|
||||
|
||||
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) ->
|
||||
switch event.getName()
|
||||
when 'BeforeFeatures'
|
||||
@ -26,40 +39,27 @@ class Flowerbox.Cucumber.Reporter
|
||||
when '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"
|
||||
|
||||
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()
|
||||
test.passed_ = true
|
||||
result.status = Flowerbox.Result.SUCCESS
|
||||
else if stepResult.isPending()
|
||||
test.message = "pending"
|
||||
result.status = Flowerbox.Result.PENDING
|
||||
else if stepResult.isUndefined()
|
||||
regexp = @step.getName()
|
||||
regexp = regexp.replace(/"[^"]+"/g, '"([^"]+)"')
|
||||
|
||||
test.message = """
|
||||
Step not defined. Define it with the following:
|
||||
|
||||
Flowerbox.#{type} /^#{regexp}$/, ->
|
||||
@pending()
|
||||
|
||||
|
||||
"""
|
||||
result.status = Flowerbox.Result.UNDEFINED
|
||||
else if stepResult.isFailed()
|
||||
result.status = Flowerbox.Result.FAILURE
|
||||
|
||||
error = stepResult.getFailureException()
|
||||
stack = (error.stack || "message\n#{file}:0").split("\n")
|
||||
|
||||
test.message = error.message
|
||||
test.trace.stack = [ 'file:1' ]
|
||||
failure = { runner: Flowerbox.environment, message: error.message, stack: stack }
|
||||
|
||||
Flowerbox.contact("finish_test", @step.getName(), [ { items_: [ test ] } ])
|
||||
result.failures.push(failure)
|
||||
|
||||
Flowerbox.contact("finish_test", result.toJSON())
|
||||
|
||||
callback()
|
||||
|
||||
|
@ -0,0 +1,4 @@
|
||||
window.onerror = (message, file, line) ->
|
||||
Flowerbox.contact("log", message)
|
||||
Flowerbox.contact("log", " #{file}:#{line}")
|
||||
|
5
lib/assets/javascripts/flowerbox/exception.js.coffee
Normal file
5
lib/assets/javascripts/flowerbox/exception.js.coffee
Normal file
@ -0,0 +1,5 @@
|
||||
class Flowerbox.Exception
|
||||
constructor: (@stack) ->
|
||||
|
||||
toJSON: ->
|
||||
{ trace: { stack: @stack } }
|
@ -7,12 +7,21 @@ class jasmine.FlowerboxReporter
|
||||
Flowerbox.contact("start_test", spec.description)
|
||||
|
||||
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.fail() if Flowerbox.fail?
|
||||
|
||||
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) ->
|
||||
Flowerbox.contact("results", (new Date().getTime()) - @time)
|
||||
|
||||
|
@ -7,9 +7,9 @@ jasmine.Spec.beforeAddMatcherResult().push ->
|
||||
if e.stack
|
||||
file = switch Flowerbox.environment
|
||||
when 'firefox'
|
||||
e.stack.split("\n")[3].replace(/^[^@]*@/, '')
|
||||
e.stack.split("\n")[3]
|
||||
when 'chrome'
|
||||
e.stack.split("\n")[4].replace(/^.*\((.*)\)$/, '$1').replace(/:[^:]+$/, '')
|
||||
e.stack.split("\n")[4]
|
||||
|
||||
@trace = { stack: [ file.replace(/^.*__F__/, '') ] }
|
||||
@trace = { stack: [ file ] }
|
||||
|
||||
|
17
lib/assets/javascripts/flowerbox/result.js.coffee
Normal file
17
lib/assets/javascripts/flowerbox/result.js.coffee
Normal 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
|
@ -3,6 +3,10 @@ require 'flowerbox-delivery'
|
||||
require 'rainbow'
|
||||
|
||||
module Flowerbox
|
||||
module CoreExt
|
||||
autoload :Module, 'flowerbox/core_ext/module'
|
||||
end
|
||||
|
||||
autoload :Runner, 'flowerbox/runner'
|
||||
|
||||
module Runner
|
||||
@ -26,12 +30,19 @@ module Flowerbox
|
||||
autoload :ResultSet, 'flowerbox/result_set'
|
||||
autoload :GatheredResult, 'flowerbox/gathered_result'
|
||||
autoload :Result, 'flowerbox/result'
|
||||
autoload :BaseResult, 'flowerbox/base_result'
|
||||
autoload :Success, 'flowerbox/success'
|
||||
autoload :Failure, 'flowerbox/failure'
|
||||
autoload :Exception, 'flowerbox/exception'
|
||||
|
||||
autoload :Reporter, 'flowerbox/reporter'
|
||||
|
||||
class << self
|
||||
attr_writer :reporters
|
||||
|
||||
def reset!
|
||||
@spec_patterns = nil
|
||||
@spec_files = nil
|
||||
@asset_paths = nil
|
||||
@reporters = nil
|
||||
end
|
||||
|
||||
def spec_patterns
|
||||
@spec_patterns ||= []
|
||||
end
|
||||
@ -40,6 +51,10 @@ module Flowerbox
|
||||
@asset_paths ||= []
|
||||
end
|
||||
|
||||
def reporters
|
||||
@reporters ||= []
|
||||
end
|
||||
|
||||
def test_with(what)
|
||||
self.test_environment = Flowerbox::TestEnvironment.for(what)
|
||||
end
|
||||
@ -48,6 +63,10 @@ module Flowerbox
|
||||
self.runner_environment = whats.flatten.collect { |what| Flowerbox::Runner.for(what.to_s) }
|
||||
end
|
||||
|
||||
def report_with(*whats)
|
||||
self.reporters = whats.flatten.collect { |what| Flowerbox::Reporter.for(what.to_s) }
|
||||
end
|
||||
|
||||
def path
|
||||
Pathname(File.expand_path('../..', __FILE__))
|
||||
end
|
||||
@ -61,6 +80,10 @@ module Flowerbox
|
||||
spec_patterns << "**/*_spec*"
|
||||
spec_patterns << "*/*_spec*"
|
||||
end
|
||||
|
||||
if reporters.empty?
|
||||
reporters << Flowerbox::Reporter.for(:progress)
|
||||
end
|
||||
end
|
||||
|
||||
def bare_coffeescript
|
||||
@ -68,6 +91,8 @@ module Flowerbox
|
||||
end
|
||||
|
||||
def run(dir, options = {})
|
||||
reset!
|
||||
|
||||
load File.join(dir, 'spec_helper.rb')
|
||||
|
||||
if options[:runners]
|
||||
@ -81,13 +106,18 @@ module Flowerbox
|
||||
|
||||
result_set = ResultSet.new
|
||||
|
||||
time = 0
|
||||
realtime = Time.now.to_i
|
||||
|
||||
Flowerbox.runner_environment.each do |env|
|
||||
env.ensure_configured!
|
||||
|
||||
result_set << env.run(build_sprockets_for(dir), spec_files_for(dir), options)
|
||||
|
||||
time += env.time
|
||||
end
|
||||
|
||||
result_set.print
|
||||
result_set.print(:time => time, :realtime => Time.now.to_i - realtime)
|
||||
result_set.exitstatus
|
||||
end
|
||||
|
||||
@ -116,7 +146,7 @@ module Flowerbox
|
||||
|
||||
Flowerbox.spec_patterns.each do |pattern|
|
||||
Dir[File.join(dir, pattern)].each do |file|
|
||||
@spec_files << file.gsub(dir + '/', '')
|
||||
@spec_files << File.expand_path(file)
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -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
|
||||
|
14
lib/flowerbox/core_ext/module.rb
Normal file
14
lib/flowerbox/core_ext/module.rb
Normal 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
|
||||
|
@ -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
|
||||
|
@ -25,16 +25,6 @@ module Flowerbox
|
||||
def success?
|
||||
@results.all?(&:success?)
|
||||
end
|
||||
|
||||
def print
|
||||
puts name.join(' ')
|
||||
|
||||
results.each do |result|
|
||||
puts " #{result}"
|
||||
end
|
||||
|
||||
puts
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -33,13 +33,17 @@ module Flowerbox
|
||||
end
|
||||
|
||||
empty_post '/finish_test' do
|
||||
runner.add_results(data.flatten[1..-1])
|
||||
runner.add_results(data.flatten)
|
||||
end
|
||||
|
||||
empty_post '/log' do
|
||||
runner.log(data.first)
|
||||
end
|
||||
|
||||
empty_post '/ping' do
|
||||
runner.ping
|
||||
end
|
||||
|
||||
get %r{^/__F__(/.*)$} do |file|
|
||||
File.read(file)
|
||||
end
|
||||
|
12
lib/flowerbox/reporter.rb
Normal file
12
lib/flowerbox/reporter.rb
Normal 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
|
||||
|
45
lib/flowerbox/reporter/base.rb
Normal file
45
lib/flowerbox/reporter/base.rb
Normal 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
|
||||
|
41
lib/flowerbox/reporter/console_base.rb
Normal file
41
lib/flowerbox/reporter/console_base.rb
Normal 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
|
||||
|
13
lib/flowerbox/reporter/file_display.rb
Normal file
13
lib/flowerbox/reporter/file_display.rb
Normal 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
|
||||
|
29
lib/flowerbox/reporter/progress.rb
Normal file
29
lib/flowerbox/reporter/progress.rb
Normal 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
|
||||
|
51
lib/flowerbox/reporter/verbose.rb
Normal file
51
lib/flowerbox/reporter/verbose.rb
Normal 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
|
||||
|
@ -1,45 +1,28 @@
|
||||
module Flowerbox
|
||||
class Result
|
||||
def <=>(other)
|
||||
result = self.name.length <=> other.name.length
|
||||
module Result
|
||||
extend Flowerbox::CoreExt::Module
|
||||
|
||||
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
|
||||
|
||||
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
|
||||
|
79
lib/flowerbox/result/base.rb
Normal file
79
lib/flowerbox/result/base.rb
Normal 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
|
||||
|
0
lib/flowerbox/result/cucumber/base.rb
Normal file
0
lib/flowerbox/result/cucumber/base.rb
Normal file
7
lib/flowerbox/result/cucumber/failure.rb
Normal file
7
lib/flowerbox/result/cucumber/failure.rb
Normal file
@ -0,0 +1,7 @@
|
||||
module Flowerbox::Result
|
||||
module Cucumber
|
||||
class Failure < Flowerbox::Result::Failure
|
||||
end
|
||||
end
|
||||
end
|
||||
|
8
lib/flowerbox/result/cucumber/pending.rb
Normal file
8
lib/flowerbox/result/cucumber/pending.rb
Normal file
@ -0,0 +1,8 @@
|
||||
module Flowerbox::Result
|
||||
module Cucumber
|
||||
class Pending < Flowerbox::Result::Pending
|
||||
|
||||
end
|
||||
end
|
||||
end
|
||||
|
7
lib/flowerbox/result/cucumber/skipped.rb
Normal file
7
lib/flowerbox/result/cucumber/skipped.rb
Normal file
@ -0,0 +1,7 @@
|
||||
module Flowerbox::Result
|
||||
module Cucumber
|
||||
class Skipped < Flowerbox::Result::Pending
|
||||
end
|
||||
end
|
||||
end
|
||||
|
10
lib/flowerbox/result/cucumber/success.rb
Normal file
10
lib/flowerbox/result/cucumber/success.rb
Normal file
@ -0,0 +1,10 @@
|
||||
module Flowerbox::Result
|
||||
module Cucumber
|
||||
class Success < Flowerbox::Result::Base
|
||||
def success?
|
||||
true
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
14
lib/flowerbox/result/cucumber/undefined.rb
Normal file
14
lib/flowerbox/result/cucumber/undefined.rb
Normal 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
|
||||
|
6
lib/flowerbox/result/exception.rb
Normal file
6
lib/flowerbox/result/exception.rb
Normal file
@ -0,0 +1,6 @@
|
||||
module Flowerbox::Result
|
||||
class Exception < Base
|
||||
|
||||
end
|
||||
end
|
||||
|
20
lib/flowerbox/result/failure.rb
Normal file
20
lib/flowerbox/result/failure.rb
Normal 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
|
||||
|
32
lib/flowerbox/result/failure_message.rb
Normal file
32
lib/flowerbox/result/failure_message.rb
Normal 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
|
||||
|
32
lib/flowerbox/result/file_info.rb
Normal file
32
lib/flowerbox/result/file_info.rb
Normal 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
|
||||
|
7
lib/flowerbox/result/jasmine/failure.rb
Normal file
7
lib/flowerbox/result/jasmine/failure.rb
Normal file
@ -0,0 +1,7 @@
|
||||
module Flowerbox::Result
|
||||
module Jasmine
|
||||
class Failure < Flowerbox::Result::Failure
|
||||
end
|
||||
end
|
||||
end
|
||||
|
8
lib/flowerbox/result/jasmine/success.rb
Normal file
8
lib/flowerbox/result/jasmine/success.rb
Normal file
@ -0,0 +1,8 @@
|
||||
module Flowerbox::Result
|
||||
module Jasmine
|
||||
class Success < Flowerbox::Result::Base
|
||||
def success? ; true ; end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
12
lib/flowerbox/result/pending.rb
Normal file
12
lib/flowerbox/result/pending.rb
Normal file
@ -0,0 +1,12 @@
|
||||
module Flowerbox::Result
|
||||
class Pending < Base
|
||||
def pending?
|
||||
true
|
||||
end
|
||||
|
||||
def failure?
|
||||
false
|
||||
end
|
||||
end
|
||||
end
|
||||
|
@ -5,21 +5,16 @@ module Flowerbox
|
||||
attr_accessor :time
|
||||
|
||||
def self.from_results(results, options)
|
||||
results = results['items_'].collect do |result|
|
||||
if name = result['splitName']
|
||||
case result['passed_']
|
||||
when true
|
||||
Success.new(name, result['message'])
|
||||
else
|
||||
Failure.new(name, result['message'], result['trace']['stack'].first)
|
||||
end
|
||||
results = results.collect do |result|
|
||||
result['runner'] = options[:runner]
|
||||
|
||||
if name = result['name']
|
||||
Flowerbox::Result.for(result['source'], result['status']).new(result)
|
||||
else
|
||||
Exception.new(result.first['trace']['stack'])
|
||||
Flowerbox::Result::Exception.new(result)
|
||||
end
|
||||
end.flatten
|
||||
|
||||
results.each { |result| result.runners << options[:runner] }
|
||||
|
||||
new(results, options)
|
||||
end
|
||||
|
||||
@ -27,6 +22,10 @@ module Flowerbox
|
||||
new(results, :runner => runner)
|
||||
end
|
||||
|
||||
def reporters
|
||||
Flowerbox.reporters
|
||||
end
|
||||
|
||||
def initialize(results = [], options = {})
|
||||
@results, @options = results, options
|
||||
end
|
||||
@ -34,7 +33,7 @@ module Flowerbox
|
||||
def <<(other)
|
||||
other.results.each do |other_result|
|
||||
if existing_result = results.find { |result| result == other_result }
|
||||
existing_result.runners << other_result.runners
|
||||
existing_result << other_result
|
||||
else
|
||||
results << other_result
|
||||
end
|
||||
@ -45,10 +44,8 @@ module Flowerbox
|
||||
@results.empty? ? 0 : 1
|
||||
end
|
||||
|
||||
def print
|
||||
gathered_results.each(&:print)
|
||||
|
||||
puts "#{total_tests} total, #{total_failures} failures, #{time} secs."
|
||||
def print(data = {})
|
||||
reporters.each { |reporter| reporter.report(flattened_gathered_results, data) }
|
||||
end
|
||||
|
||||
def total_tests
|
||||
@ -60,7 +57,9 @@ module Flowerbox
|
||||
end
|
||||
|
||||
def print_progress
|
||||
@results.each { |result| result.print_progress ; $stdout.flush }
|
||||
@results.each do |result|
|
||||
reporters.each { |reporter| reporter.report_progress(result) }
|
||||
end
|
||||
end
|
||||
|
||||
def gathered_results
|
||||
@ -69,22 +68,21 @@ module Flowerbox
|
||||
@gathered_results = []
|
||||
|
||||
results.each do |result|
|
||||
case result
|
||||
when Flowerbox::Exception
|
||||
@gathered_results << result
|
||||
when Flowerbox::Failure
|
||||
if !(gathered_result = @gathered_results.find { |g| g.name == result.name })
|
||||
gathered_result = GatheredResult.new(result.name)
|
||||
if !(gathered_result = @gathered_results.find { |g| g.name == result.name })
|
||||
gathered_result = GatheredResult.new(result.name)
|
||||
|
||||
@gathered_results << gathered_result
|
||||
end
|
||||
|
||||
gathered_result << result
|
||||
@gathered_results << gathered_result
|
||||
end
|
||||
|
||||
gathered_result << result
|
||||
end
|
||||
|
||||
@gathered_results
|
||||
end
|
||||
|
||||
def flattened_gathered_results
|
||||
gathered_results.collect(&:results).flatten
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -1,10 +1,6 @@
|
||||
module Flowerbox
|
||||
module Runner
|
||||
class << self
|
||||
def for(env)
|
||||
self.const_get(self.constants.find { |c| c.to_s.downcase.to_s == env.to_s }).new
|
||||
end
|
||||
end
|
||||
extend Flowerbox::CoreExt::Module
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -1,17 +1,28 @@
|
||||
module Flowerbox
|
||||
module Runner
|
||||
class Base
|
||||
attr_reader :sprockets, :spec_files, :options
|
||||
attr_reader :sprockets, :spec_files, :options, :time
|
||||
|
||||
attr_accessor :results
|
||||
|
||||
MAX_COUNT = 30
|
||||
|
||||
def initialize
|
||||
@results = ResultSet.new
|
||||
end
|
||||
|
||||
def ensure_alive
|
||||
while @count < MAX_COUNT && !finished?
|
||||
@count += 1
|
||||
sleep 0.1
|
||||
end
|
||||
end
|
||||
|
||||
def run(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}..."
|
||||
|
||||
server.start
|
||||
@ -20,9 +31,6 @@ module Flowerbox
|
||||
|
||||
server.stop
|
||||
|
||||
puts
|
||||
puts
|
||||
|
||||
@results
|
||||
end
|
||||
|
||||
@ -56,7 +64,7 @@ module Flowerbox
|
||||
return @server if @server
|
||||
|
||||
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)
|
||||
Flowerbox::Rack.runner = self
|
||||
@ -74,6 +82,8 @@ module Flowerbox
|
||||
|
||||
def add_tests(new_tests)
|
||||
tests << new_tests
|
||||
|
||||
@count = 0
|
||||
end
|
||||
|
||||
def failures
|
||||
@ -96,6 +106,10 @@ module Flowerbox
|
||||
@failures.length
|
||||
end
|
||||
|
||||
def time
|
||||
@time ||= 0
|
||||
end
|
||||
|
||||
def finish!(time)
|
||||
@time = time
|
||||
|
||||
@ -106,9 +120,13 @@ module Flowerbox
|
||||
@finished
|
||||
end
|
||||
|
||||
def ping
|
||||
@count = 0
|
||||
end
|
||||
|
||||
private
|
||||
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
|
||||
|
@ -3,7 +3,6 @@ require 'selenium-webdriver'
|
||||
module Flowerbox
|
||||
module Runner
|
||||
class Selenium < Base
|
||||
MAX_COUNT = 30
|
||||
|
||||
def name
|
||||
raise StandardError.new("Override me")
|
||||
@ -20,12 +19,7 @@ module Flowerbox
|
||||
|
||||
selenium.navigate.to "http://localhost:#{server.port}/"
|
||||
|
||||
@count = 0
|
||||
|
||||
while @count < MAX_COUNT && !finished?
|
||||
@count += 1
|
||||
sleep 0.1
|
||||
end
|
||||
ensure_alive
|
||||
ensure
|
||||
selenium.quit if selenium
|
||||
end
|
||||
@ -60,7 +54,9 @@ console.log = function(msg) {
|
||||
|
||||
var context = this;
|
||||
|
||||
#{env}
|
||||
window.onload = function() {
|
||||
#{env}
|
||||
};
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
@ -70,12 +66,6 @@ HTML
|
||||
def template_files
|
||||
sprockets.files.collect { |file| %{<script type="text/javascript" src="/__F__#{file}"></script>} }
|
||||
end
|
||||
|
||||
def add_failures(data)
|
||||
super
|
||||
|
||||
@count = 0
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
@ -1,8 +1,10 @@
|
||||
module Flowerbox
|
||||
module TestEnvironment
|
||||
extend Flowerbox::CoreExt::Module
|
||||
|
||||
class << self
|
||||
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
|
||||
|
@ -10,10 +10,12 @@ module Flowerbox
|
||||
end
|
||||
|
||||
def start_for(runner)
|
||||
@runner = runner
|
||||
|
||||
@sprockets.add("flowerbox/cucumber")
|
||||
@sprockets.add("flowerbox/cucumber/#{runner.type}")
|
||||
|
||||
runner.spec_files.each { |file| @sprockets.add(file) }
|
||||
@runner.spec_files.each { |file| @sprockets.add(file) }
|
||||
|
||||
<<-JS
|
||||
context.Cucumber = context.require('./cucumber');
|
||||
@ -23,6 +25,43 @@ context.cucumber.attachListener(new context.Flowerbox.Cucumber.Reporter());
|
||||
context.cucumber.start(function() {});
|
||||
JS
|
||||
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
|
||||
|
@ -25,18 +25,9 @@ if (typeof context != 'undefined' && typeof jasmine == 'undefined') {
|
||||
}
|
||||
|
||||
jasmine.getEnv().addReporter(new jasmine.FlowerboxReporter());
|
||||
#{jasmine_reporters.join("\n")}
|
||||
jasmine.getEnv().execute();
|
||||
JS
|
||||
end
|
||||
|
||||
def jasmine_reporters
|
||||
reporters.collect { |reporter| %{jasmine.getEnv().addReporter(new jasmine.#{reporter}());} }
|
||||
end
|
||||
|
||||
def reporters
|
||||
@reporters ||= []
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
Loading…
Reference in New Issue
Block a user