├── .travis.yml ├── Gemfile ├── Gemfile.lock ├── MIT-LICENSE ├── Rakefile ├── Readme.md ├── lib └── rspec │ ├── instafail.rb │ └── instafail │ ├── rspec_1.rb │ ├── rspec_2.rb │ ├── rspec_3.rb │ └── version.rb ├── rspec-instafail.gemspec └── spec ├── instafail_spec.rb ├── rspec_1 ├── Gemfile ├── Gemfile.lock └── a_test.rb ├── rspec_2 ├── Gemfile ├── Gemfile.lock └── a_test.rb └── rspec_3 ├── Gemfile ├── Gemfile.lock └── a_test.rb /.travis.yml: -------------------------------------------------------------------------------- 1 | language: ruby 2 | cache: bundler 3 | rvm: 2.3.1 4 | -------------------------------------------------------------------------------- /Gemfile: -------------------------------------------------------------------------------- 1 | source "https://rubygems.org" 2 | 3 | gemspec 4 | 5 | gem "bump" 6 | gem "rake" 7 | -------------------------------------------------------------------------------- /Gemfile.lock: -------------------------------------------------------------------------------- 1 | PATH 2 | remote: . 3 | specs: 4 | rspec-instafail (1.0.0) 5 | rspec 6 | 7 | GEM 8 | remote: https://rubygems.org/ 9 | specs: 10 | bump (0.8.0) 11 | diff-lcs (1.3) 12 | rake (13.0.1) 13 | rspec (3.9.0) 14 | rspec-core (~> 3.9.0) 15 | rspec-expectations (~> 3.9.0) 16 | rspec-mocks (~> 3.9.0) 17 | rspec-core (3.9.1) 18 | rspec-support (~> 3.9.1) 19 | rspec-expectations (3.9.0) 20 | diff-lcs (>= 1.2.0, < 2.0) 21 | rspec-support (~> 3.9.0) 22 | rspec-mocks (3.9.0) 23 | diff-lcs (>= 1.2.0, < 2.0) 24 | rspec-support (~> 3.9.0) 25 | rspec-support (3.9.2) 26 | 27 | PLATFORMS 28 | ruby 29 | 30 | DEPENDENCIES 31 | bump 32 | rake 33 | rspec-instafail! 34 | -------------------------------------------------------------------------------- /MIT-LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (C) 2013 Michael Grosser 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining 4 | a copy of this software and associated documentation files (the 5 | "Software"), to deal in the Software without restriction, including 6 | without limitation the rights to use, copy, modify, merge, publish, 7 | distribute, sublicense, and/or sell copies of the Software, and to 8 | permit persons to whom the Software is furnished to do so, subject to 9 | the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be 12 | included in all copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 15 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 16 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 17 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 18 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 19 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 20 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | -------------------------------------------------------------------------------- /Rakefile: -------------------------------------------------------------------------------- 1 | require "bundler/setup" 2 | require "bundler/gem_tasks" 3 | require "bump/tasks" 4 | 5 | task :default do 6 | Bundler.with_clean_env do 7 | sh "cd spec/rspec_1 && (bundle check || bundle) > /dev/null" 8 | sh "cd spec/rspec_2 && (bundle check || bundle) > /dev/null" 9 | sh "cd spec/rspec_3 && (bundle check || bundle) > /dev/null" 10 | end 11 | sh "rspec spec/instafail_spec.rb" 12 | end 13 | -------------------------------------------------------------------------------- /Readme.md: -------------------------------------------------------------------------------- 1 | # rspec-instafail 2 | [![Gem Version](https://badge.fury.io/rb/rspec-instafail.svg)](https://rubygems.org/gems/rspec-instafail) 3 | [![Build Status](https://travis-ci.org/grosser/rspec-instafail.svg)](https://travis-ci.org/grosser/rspec-instafail) 4 | 5 | Show failing specs instantly. Show passing spec as green dots as usual. 6 | 7 | **Upgrading to 1.0 ?** add `--format progress` 8 | 9 | Output 10 | ====== 11 | 12 | ``` 13 | ....................................................*.... 14 | 1) ApplicationController#sign_out_and_redirect with JSON should return JSON indicating success 15 | Failure/Error: json_response = JSON.parse response.body 16 | A JSON text must at least contain two octets! 17 | # /Users/miwillhite/.rvm/gems/ruby-1.9.2-p0/gems/json_pure-1.4.6/lib/json/common.rb:146:in `initialize' 18 | # /Users/miwillhite/.rvm/gems/ruby-1.9.2-p0/gems/json_pure-1.4.6/lib/json/common.rb:146:in `new' 19 | # /Users/miwillhite/.rvm/gems/ruby-1.9.2-p0/gems/json_pure-1.4.6/lib/json/common.rb:146:in `parse' 20 | # ./spec/controllers/application_controller_spec.rb:17:in `block (4 levels) in ' 21 | .................................................................. 22 | 23 | Finished in 650.095614 seconds 24 | 25 | 1680 examples, 1 failure, 1 pending 26 | ``` 27 | 28 | 29 | 30 | Install 31 | ======= 32 | 33 | Rspec 2.x and higher 34 | -------------------- 35 | 36 | ```Bash 37 | gem install rspec-instafail 38 | 39 | # .rspec 40 | --require rspec/instafail 41 | --format RSpec::Instafail 42 | --format progress # to keep dots appear 43 | ``` 44 | 45 | Rspec 1.x 46 | --------- 47 | 48 | You have to use the version 0.4.0 with this version of Rspec. See the [0.4.0 branch](https://github.com/grosser/rspec-instafail/tree/v0.4). 49 | 50 | Alternatives 51 | ============ 52 | 53 | Use built-in `--fail-fast` 54 | 55 | Authors 56 | ======= 57 | 58 | ### [Contributors](http://github.com/grosser/rspec-instafail/contributors) 59 | - [Matthew Willhite](http://github.com/miwillhite) 60 | - [Jeff Kreeftmeijer](http://jeffkreeftmeijer.com) 61 | - [Steve Tooke](http://tooky.github.com) 62 | - [Josh Ellithorpe](https://github.com/zquestz) 63 | - [Raphael Sofaer](https://github.com/rsofaer) 64 | - [Mike Mazur](https://github.com/mikem) 65 | - [vernonR2](https://github.com/vernonR2) 66 | - [Olek Janiszewski](https://github.com/exviva) 67 | - [Kevin Carter](https://github.com/DexterTheDragon) 68 | 69 | [Michael Grosser](http://grosser.it)
70 | michael@grosser.it
71 | License: MIT 72 | -------------------------------------------------------------------------------- /lib/rspec/instafail.rb: -------------------------------------------------------------------------------- 1 | module RSpec 2 | gem_spec = Gem::Specification.find_all_by_name('rspec-core').first 3 | if gem_spec 4 | version = gem_spec.version 5 | require "rspec/instafail/rspec_#{[3, version.segments.first].min}" 6 | else 7 | require "rspec/instafail/rspec_1" 8 | end 9 | end 10 | -------------------------------------------------------------------------------- /lib/rspec/instafail/rspec_1.rb: -------------------------------------------------------------------------------- 1 | require 'spec/runner/formatter/progress_bar_formatter' 2 | 3 | module RSpec 4 | class Instafail < Spec::Runner::Formatter::ProgressBarFormatter 5 | def example_failed(example, counter, failure) 6 | dump_failure(counter, failure) 7 | end 8 | end 9 | end 10 | -------------------------------------------------------------------------------- /lib/rspec/instafail/rspec_2.rb: -------------------------------------------------------------------------------- 1 | require 'rspec/core/formatters/progress_formatter' 2 | 3 | module RSpec 4 | class Instafail < RSpec::Core::Formatters::ProgressFormatter 5 | def example_failed(example) 6 | # do what BaseFormatter#example_failed would do 7 | @failed_examples << example 8 | 9 | # do what BaseTextFormatter#dump_failures would do 10 | index = failed_examples.size - 1 11 | _dump_pending_example(example, index) 12 | dump_backtrace(example) 13 | end 14 | 15 | private 16 | 17 | def _dump_pending_example(example, index) 18 | if defined? pending_fixed? # > 2.8 19 | if pending_fixed?(example) 20 | dump_pending_fixed(example, index) 21 | else 22 | preserve_size(example.example_group.ancestors) do 23 | dump_failure(example, index) 24 | end 25 | end 26 | else 27 | dump_pending_example_fixed(example, index) || dump_failure(example, index) 28 | end 29 | end 30 | 31 | def preserve_size(array) 32 | old = array.size 33 | yield 34 | array.pop if array.size > old 35 | end 36 | end 37 | end 38 | -------------------------------------------------------------------------------- /lib/rspec/instafail/rspec_3.rb: -------------------------------------------------------------------------------- 1 | require 'rspec/core/formatters/base_formatter' 2 | 3 | module RSpec 4 | class Instafail < RSpec::Core::Formatters::BaseFormatter 5 | RSpec::Core::Formatters.register self, :example_failed 6 | 7 | def initialize(output) 8 | super 9 | @failed_examples = [] 10 | end 11 | 12 | def example_failed(failure) 13 | @failed_examples << failure.example 14 | output.puts failure.fully_formatted(@failed_examples.size) 15 | end 16 | end 17 | end 18 | -------------------------------------------------------------------------------- /lib/rspec/instafail/version.rb: -------------------------------------------------------------------------------- 1 | module RSpec 2 | class Instafail 3 | VERSION = '1.0.0' 4 | end 5 | end 6 | -------------------------------------------------------------------------------- /rspec-instafail.gemspec: -------------------------------------------------------------------------------- 1 | name = 'rspec-instafail' 2 | require './lib/rspec/instafail/version' 3 | 4 | Gem::Specification.new name, RSpec::Instafail::VERSION do |s| 5 | s.summary = "Show failing specs instantly" 6 | s.authors = ["Michael Grosser"] 7 | s.email = "michael@grosser.it" 8 | s.homepage = "https://github.com/grosser/#{name}" 9 | s.files = `git ls-files lib Readme.md`.split("\n") 10 | s.license = "MIT" 11 | s.add_runtime_dependency "rspec" 12 | end 13 | -------------------------------------------------------------------------------- /spec/instafail_spec.rb: -------------------------------------------------------------------------------- 1 | RSpec.configure do |config| 2 | config.expect_with(:rspec) { |c| c.syntax = :should } 3 | config.mock_with(:rspec) { |c| c.syntax = :should } 4 | end 5 | 6 | describe 'RSpec::Instafail' do 7 | context "RSpec 1.x" do 8 | before :all do 9 | Bundler.with_clean_env do 10 | @rspec_result = `cd spec/rspec_1 && bundle exec spec a_test.rb --format RSpec::Instafail` 11 | end 12 | end 13 | 14 | before do 15 | @output = @rspec_result.dup 16 | end 17 | 18 | it "outputs failures at start of output" do 19 | @output.should =~ /^\s*1\)\s*'x fails logically'/m 20 | end 21 | 22 | it 'outputs errors in middle of output' do 23 | @output.should =~ /\.\.\*\s*2\)\s*RuntimeError in 'x raises a simple error'/m 24 | end 25 | 26 | it 'outputs the the ending block' do 27 | @output.should =~ /Finished in \d\.\d+ seconds\s*7 examples, 3 failures, 1 pending/ 28 | end 29 | end 30 | 31 | context 'Rspec 2.x' do 32 | before :all do 33 | Bundler.with_clean_env do 34 | @rspec_result = `cd spec/rspec_2 && bundle exec rspec a_test.rb -I ../../lib --require rspec/instafail --format RSpec::Instafail --no-color --order defined` 35 | end 36 | end 37 | 38 | before do 39 | @output = @rspec_result.dup 40 | end 41 | 42 | it "outputs failures at start of output" do 43 | @output.should =~ /^\s+1\) x fails logically/m 44 | end 45 | 46 | it 'outputs errors in middle of output' do 47 | @output.should =~ /\.\.\*\s*2\) x raises a simple error/m 48 | end 49 | 50 | it 'outputs the the ending block' do 51 | @output.should =~ /Finished in \d\.\d+ seconds\s*9 examples, 4 failures, 1 pending/ 52 | end 53 | 54 | it "does not add ancestors after failures" do 55 | @output.should include('ANCESTORS:17') 56 | @output.should_not include('ANCESTORS:18') 57 | end 58 | end 59 | 60 | context 'Rspec 3.x' do 61 | before :all do 62 | Bundler.with_clean_env do 63 | @rspec_result = `cd spec/rspec_3 && bundle exec rspec a_test.rb -I ../../lib --require rspec/instafail --format RSpec::Instafail --format progress --no-color --order defined` 64 | end 65 | end 66 | 67 | before do 68 | @output = @rspec_result.dup 69 | end 70 | 71 | it "outputs failures at start of output" do 72 | @output.should =~ /^\s+1\) x fails logically/m 73 | end 74 | 75 | it 'outputs errors in middle of output' do 76 | @output.should =~ /\.\.\*\s*2\) x raises a simple error/m 77 | end 78 | 79 | it 'outputs the the ending block' do 80 | @output.should =~ /Finished in \d\.\d+ seconds.*\s*9 examples, 4 failures, 1 pending/ 81 | end 82 | 83 | it "does not add ancestors after failures" do 84 | @output.should include('ANCESTORS:18') 85 | @output.should_not include('ANCESTORS:19') 86 | end 87 | end 88 | end 89 | -------------------------------------------------------------------------------- /spec/rspec_1/Gemfile: -------------------------------------------------------------------------------- 1 | source 'https://rubygems.org' 2 | gem 'rspec', '~> 1.3' 3 | -------------------------------------------------------------------------------- /spec/rspec_1/Gemfile.lock: -------------------------------------------------------------------------------- 1 | GEM 2 | remote: https://rubygems.org/ 3 | specs: 4 | rspec (1.3.0) 5 | 6 | PLATFORMS 7 | ruby 8 | 9 | DEPENDENCIES 10 | rspec (~> 1.3) 11 | -------------------------------------------------------------------------------- /spec/rspec_1/a_test.rb: -------------------------------------------------------------------------------- 1 | require File.expand_path(File.join(File.dirname(__FILE__), '..', '..', 'lib', 'rspec', 'instafail')) 2 | 3 | describe 'x' do 4 | it 'fails logically' do 5 | 1.should == 2 6 | end 7 | 8 | it 'b' do 9 | end 10 | 11 | it 'c' do 12 | end 13 | 14 | it 'pends' do 15 | pending 16 | raise 17 | end 18 | 19 | it 'raises a simple error' do 20 | raise 'shallow failure' 21 | end 22 | 23 | it 'raises a hidden error' do 24 | error = ExceptionWrappingException.new('There is an error in this error.') 25 | error.original_exception = RuntimeError.new('There is no error in this error.') 26 | raise error 27 | end 28 | 29 | it 'e' do 30 | end 31 | end 32 | 33 | class ExceptionWrappingException < RuntimeError 34 | attr_accessor :original_exception 35 | end 36 | -------------------------------------------------------------------------------- /spec/rspec_2/Gemfile: -------------------------------------------------------------------------------- 1 | source 'https://rubygems.org' 2 | gem 'rspec', '~> 2.2' 3 | 4 | -------------------------------------------------------------------------------- /spec/rspec_2/Gemfile.lock: -------------------------------------------------------------------------------- 1 | GEM 2 | remote: https://rubygems.org/ 3 | specs: 4 | diff-lcs (1.2.5) 5 | rspec (2.99.0) 6 | rspec-core (~> 2.99.0) 7 | rspec-expectations (~> 2.99.0) 8 | rspec-mocks (~> 2.99.0) 9 | rspec-core (2.99.2) 10 | rspec-expectations (2.99.2) 11 | diff-lcs (>= 1.1.3, < 2.0) 12 | rspec-mocks (2.99.2) 13 | 14 | PLATFORMS 15 | ruby 16 | 17 | DEPENDENCIES 18 | rspec (~> 2.2) 19 | -------------------------------------------------------------------------------- /spec/rspec_2/a_test.rb: -------------------------------------------------------------------------------- 1 | require File.expand_path(File.join(File.dirname(__FILE__), '..', '..', 'lib', 'rspec', 'instafail')) 2 | 3 | describe 'x' do 4 | it 'fails logically' do 5 | 1.should == 2 6 | end 7 | 8 | it 'b' do 9 | end 10 | 11 | it 'c' do 12 | end 13 | 14 | it 'pends' do 15 | skip 16 | raise 17 | end 18 | 19 | it 'raises a simple error' do 20 | raise 'shallow failure' 21 | end 22 | 23 | it 'raises a hidden error' do 24 | error = ExceptionWrappingException.new('There is an error in this error.') 25 | error.original_exception = RuntimeError.new('There is no error in this error.') 26 | raise error 27 | end 28 | 29 | it 'e' do 30 | end 31 | 32 | context "ancestors" do 33 | after do |example| 34 | puts "ANCESTORS:#{example.example_group.ancestors.size}" 35 | end 36 | 37 | it "does not add ancestors on failure" do 38 | raise "BAM" 39 | end 40 | 41 | it "does not add ancestors on failure" do 42 | end 43 | end 44 | end 45 | 46 | class ExceptionWrappingException < RuntimeError 47 | attr_accessor :original_exception 48 | end 49 | -------------------------------------------------------------------------------- /spec/rspec_3/Gemfile: -------------------------------------------------------------------------------- 1 | source 'https://rubygems.org' 2 | gem 'rspec', '~> 3.0' 3 | -------------------------------------------------------------------------------- /spec/rspec_3/Gemfile.lock: -------------------------------------------------------------------------------- 1 | GEM 2 | remote: https://rubygems.org/ 3 | specs: 4 | diff-lcs (1.2.5) 5 | rspec (3.1.0) 6 | rspec-core (~> 3.1.0) 7 | rspec-expectations (~> 3.1.0) 8 | rspec-mocks (~> 3.1.0) 9 | rspec-core (3.1.7) 10 | rspec-support (~> 3.1.0) 11 | rspec-expectations (3.1.2) 12 | diff-lcs (>= 1.2.0, < 2.0) 13 | rspec-support (~> 3.1.0) 14 | rspec-mocks (3.1.3) 15 | rspec-support (~> 3.1.0) 16 | rspec-support (3.1.2) 17 | 18 | PLATFORMS 19 | ruby 20 | 21 | DEPENDENCIES 22 | rspec (~> 3.0) 23 | -------------------------------------------------------------------------------- /spec/rspec_3/a_test.rb: -------------------------------------------------------------------------------- 1 | require File.expand_path(File.join(File.dirname(__FILE__), '..', '..', 'lib', 'rspec', 'instafail')) 2 | 3 | describe 'x' do 4 | it 'fails logically' do 5 | expect(1).to eq 2 6 | end 7 | 8 | it 'b' do 9 | end 10 | 11 | it 'c' do 12 | end 13 | 14 | it 'pends' do 15 | pending 16 | raise 17 | end 18 | 19 | it 'raises a simple error' do 20 | raise 'shallow failure' 21 | end 22 | 23 | it 'raises a hidden error' do 24 | error = ExceptionWrappingException.new('There is an error in this error.') 25 | error.original_exception = RuntimeError.new('There is no error in this error.') 26 | raise error 27 | end 28 | 29 | it 'e' do 30 | end 31 | 32 | context "ancestors" do 33 | after do |example| 34 | puts "ANCESTORS:#{example.example_group.ancestors.size}" 35 | end 36 | 37 | it "does not add ancestors on failure" do 38 | raise "BAM" 39 | end 40 | 41 | it "does not add ancestors on failure" do 42 | end 43 | end 44 | end 45 | 46 | class ExceptionWrappingException < RuntimeError 47 | attr_accessor :original_exception 48 | end 49 | --------------------------------------------------------------------------------