diff --git a/.gitignore b/.gitignore index 44a1b60..4c7f2c0 100644 --- a/.gitignore +++ b/.gitignore @@ -18,4 +18,5 @@ tmp .tmp node_modules/ .tmp-sprockets/ - +_site/ +.sass-cache/ diff --git a/bin/flowerbox b/bin/flowerbox index aa8ecf7..441b0d6 100755 --- a/bin/flowerbox +++ b/bin/flowerbox @@ -6,7 +6,19 @@ require 'thor' class Flowerbox::CLI < Thor include Thor::Actions - desc "test", "Run the specs found in spec dir, loading spec_helper.rb for configuration details" + default_task :help + + def help(*args) + if !args.first + puts "Flowerbox is a multi-environment, multi-runner JavaScript testing tool." + puts "It supports Jasmine and Cucumber.js, and it runs tests on Node.js and Selenium-driven browsers." + puts + end + + super + end + + desc "test [DIR]", "Run the specs found in spec dir, loading spec_helper.rb for configuration details" method_options :pwd => :string, :env_options => nil, :runners => :string, :runner => :string, :verbose_server => false def test(dir = "spec/javascripts", *files) Dir.chdir(pwd) do @@ -24,7 +36,21 @@ class Flowerbox::CLI < Thor end end - desc "transplant DIR", "Convert an existing Jasmine gem-style project to Flowerbox" + desc "transplant DIR", "Convert an existing JavaScript testing project to Flowerbox" + long_desc <<-TXT + `flowerbox transplant` converts an existing JavaScript testing project type + to Flowerbox. Currently, you can transplant the following types of projects: + + * Pivotal Labs Jasmine gem-style + \x5 (also covers jasmine-headless-webkit) + + These types of projects live in `spec/javascripts` (or the specified directory) + and have the file `support/jasmine.yml` that defines what files are loaded + at what parts in the test load process. `jasmine.yml` is converted to a + Flowerbox `spec_helper.rb` file and placed into `spec/javascripts`. + + Flowerbox will ask before overwriting existing files. + TXT def transplant(dir) Flowerbox.transplant(dir) end @@ -35,7 +61,7 @@ class Flowerbox::CLI < Thor puts "Sprockets cache cleaned." end - desc "plant", "Start a new Flowerbox project" + desc "plant TYPE [DIR]", "Start a new Flowerbox project of TYPE, potentially specifying a different DIR to install" def plant(type, dir = nil) env = Flowerbox::TestEnvironment.for(type) @@ -44,16 +70,18 @@ class Flowerbox::CLI < Thor directory('.', dir || env.plant_target) end - default_task :test + def method_missing(method, *args) + if File.directory?(method.to_s) + test(method.to_s, *args) + else + super + end + end no_tasks do def pwd options[:pwd] || Dir.pwd end - - def asset_paths - Flowerbox.asset_paths.collect { |path| File.join(pwd, path) } - end end end diff --git a/lib/flowerbox.rb b/lib/flowerbox.rb index 8c9caa2..1e767fe 100644 --- a/lib/flowerbox.rb +++ b/lib/flowerbox.rb @@ -1,5 +1,6 @@ require "flowerbox/version" require 'rainbow' +require 'forwardable' module Flowerbox require 'flowerbox/core_ext/module' @@ -16,70 +17,29 @@ module Flowerbox require 'flowerbox/gathered_result' require 'flowerbox/reporter' + require 'flowerbox/configuration' if defined?(Rails::Engine) require 'flowerbox/rails/engine' end - CACHE_DIR = '.tmp-sprockets' + CACHE_DIR = 'tmp/sprockets' class << self - attr_writer :reporters - attr_accessor :port - def reset! - @spec_patterns = nil - @spec_files = nil - @asset_paths = nil - @reporters = nil - @port = nil + @configuration = nil end - def spec_patterns - @spec_patterns ||= [] - end - - def asset_paths - @asset_paths ||= [] - end - - def reporters - @reporters ||= [] - end - - def additional_files - @additional_files ||= [] - end - - def test_with(what) - self.test_environment = Flowerbox::TestEnvironment.for(what) - end - - def run_with(*whats) - 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) } + def configuration + @configuration ||= Flowerbox::Configuration.new end def path Pathname(File.expand_path('../..', __FILE__)) end - attr_accessor :test_environment, :runner_environment, :bare_coffeescript, :server - - def configure - yield self - - if spec_patterns.empty? - spec_patterns << "**/*_spec*" - spec_patterns << "*/*_spec*" - end - - if reporters.empty? - reporters << Flowerbox::Reporter.for(:progress) - end + def configure(&block) + configuration.configure(&block) end def bare_coffeescript @@ -115,6 +75,18 @@ module Flowerbox break if env.transplant(dir) end end + + def cache_dir + File.join(CACHE_DIR, Flowerbox.test_environment.name) + end + + def method_missing(method, *args) + if configuration.respond_to?(method) + configuration.send(method, *args) + else + super + end + end end end diff --git a/lib/flowerbox/configuration.rb b/lib/flowerbox/configuration.rb new file mode 100644 index 0000000..1ba758a --- /dev/null +++ b/lib/flowerbox/configuration.rb @@ -0,0 +1,54 @@ +module Flowerbox + class Configuration + attr_writer :reporters, :backtrace_filter + attr_accessor :port + + attr_accessor :test_environment, :runner_environment, :bare_coffeescript, :server + + def spec_patterns + @spec_patterns ||= [] + end + + def asset_paths + @asset_paths ||= [] + end + + def reporters + @reporters ||= [] + end + + def additional_files + @additional_files ||= [] + end + + def backtrace_filter + @backtrace_filter ||= [] + end + + def test_with(what) + self.test_environment = Flowerbox::TestEnvironment.for(what) + end + + def run_with(*whats) + 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 configure + yield self + + if spec_patterns.empty? + spec_patterns << "**/*_spec*" + spec_patterns << "*/*_spec*" + end + + if reporters.empty? + reporters << Flowerbox::Reporter.for(:progress) + end + end + end +end + diff --git a/lib/flowerbox/reporter/console_base.rb b/lib/flowerbox/reporter/console_base.rb index 7d1fdbe..de167d9 100644 --- a/lib/flowerbox/reporter/console_base.rb +++ b/lib/flowerbox/reporter/console_base.rb @@ -20,7 +20,7 @@ module Flowerbox::Reporter puts result.name.join(" - ").foreground(:red) result.failures.each do |failure| puts " " + failure.message.foreground(:red) + " [" + failure.runners.join(',') + "] " + path_for(failure) - puts failure.stack.join("\n").foreground(:red) if failure.exception? + puts failure.filtered_stack.join("\n").foreground(:red) if failure.exception? end end diff --git a/lib/flowerbox/reporter/verbose.rb b/lib/flowerbox/reporter/verbose.rb index 6cf2b32..02f8e71 100644 --- a/lib/flowerbox/reporter/verbose.rb +++ b/lib/flowerbox/reporter/verbose.rb @@ -12,6 +12,8 @@ module Flowerbox::Reporter if result.name result.name.each_with_index do |name, index| if @name_stack[index] != name + @name_stack = [] + if name != result.name.last message = name else diff --git a/lib/flowerbox/result/failure_message.rb b/lib/flowerbox/result/failure_message.rb index 6dc5c2a..0f4f036 100644 --- a/lib/flowerbox/result/failure_message.rb +++ b/lib/flowerbox/result/failure_message.rb @@ -34,6 +34,19 @@ module Flowerbox::Result @data['stack'] || [] end + def filtered_stack + filtered_stack = stack.reject { |line| + Flowerbox.backtrace_filter.any? { |filter| line[filter] } + }.collect { |line| + line.gsub(%r{\.coffee:(\d+)}) do |_| + ".coffee:~#{($1.to_i * 0.67 + 1).to_i}" + end + } + + filtered_stack.shift if exception? + filtered_stack + end + def first_local_stack @first_local_stack ||= stack[1..-1].find do |line| !system_files.any? { |file| line[%r{\(#{file}}] } @@ -41,7 +54,7 @@ module Flowerbox::Result end def exception? - stack[0][%r{^.+Error: }] + (stack[0] || '')[%r{^.+Error: }] end end end diff --git a/lib/flowerbox/run/base.rb b/lib/flowerbox/run/base.rb index fe2e134..418c3a2 100644 --- a/lib/flowerbox/run/base.rb +++ b/lib/flowerbox/run/base.rb @@ -35,14 +35,16 @@ module Flowerbox::Run def sprockets require 'flowerbox/sprockets_handler' - Flowerbox::SprocketsHandler.new( - :asset_paths => [ - Flowerbox.path.join("lib/assets/javascripts"), - Flowerbox.path.join("vendor/assets/javascripts"), - @dir, - Flowerbox.asset_paths - ].flatten - ) + Flowerbox::SprocketsHandler.new(:asset_paths => asset_paths) + end + + def asset_paths + [ + Flowerbox.path.join("lib/assets/javascripts"), + Flowerbox.path.join("vendor/assets/javascripts"), + @dir, + Flowerbox.asset_paths + ].flatten end def spec_files diff --git a/lib/flowerbox/runner/base.rb b/lib/flowerbox/runner/base.rb index 4ccedfc..e63ee9d 100644 --- a/lib/flowerbox/runner/base.rb +++ b/lib/flowerbox/runner/base.rb @@ -57,7 +57,20 @@ module Flowerbox puts "Flowerbox running your #{Flowerbox.test_environment.name} tests on #{console_name}..." - server.start + attempts = 3 + + while true + begin + server.start + + break + rescue Flowerbox::Server::ServerDiedError + attempts -= 1 + raise RunnerDiedError.new if attempts == 0 + + Flowerbox.server = nil + end + end yield diff --git a/lib/flowerbox/runner/selenium.rb b/lib/flowerbox/runner/selenium.rb index 770389c..602668b 100644 --- a/lib/flowerbox/runner/selenium.rb +++ b/lib/flowerbox/runner/selenium.rb @@ -38,6 +38,10 @@ module Flowerbox