├── .gitignore ├── .travis.yml ├── CHANGELOG.md ├── Gemfile ├── LICENSE.txt ├── README.md ├── Rakefile ├── acceptance ├── .gitignore ├── rspec_example_spec.rb └── verification_spec.rb ├── ci_reporter_rspec.gemspec ├── gemfiles ├── .gitignore ├── Gemfile.2.14 └── Gemfile.2.99 ├── lib └── ci │ └── reporter │ ├── rake │ ├── rspec.rb │ └── rspec_loader.rb │ ├── rspec.rb │ ├── rspec │ └── version.rb │ ├── rspec2 │ ├── failure.rb │ └── formatter.rb │ └── rspec3 │ ├── failure.rb │ └── formatter.rb └── spec ├── ci └── reporter │ ├── rake │ └── rake_tasks_spec.rb │ └── rspec2 │ ├── failure_spec.rb │ └── formatter_spec.rb ├── spec_helper.rb └── support └── rspec2.rb /.gitignore: -------------------------------------------------------------------------------- 1 | *.gem 2 | *.rbc 3 | .bundle 4 | .config 5 | .yardoc 6 | Gemfile.lock 7 | InstalledFiles 8 | _yardoc 9 | coverage 10 | doc/ 11 | lib/bundler/man 12 | pkg 13 | rdoc 14 | spec/reports 15 | test/tmp 16 | test/version_tmp 17 | tmp 18 | *.bundle 19 | *.so 20 | *.o 21 | *.a 22 | mkmf.log 23 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | rvm: 2 | - 1.9.3 3 | - 2.0 4 | - 2.1 5 | - jruby 6 | 7 | gemfile: 8 | - Gemfile 9 | - gemfiles/Gemfile.2.14 10 | - gemfiles/Gemfile.2.99 11 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | ## 1.0.0 (2014-07-24) 2 | 3 | The first release after being separated from `ci_reporter`. 4 | 5 | ### Changes 6 | 7 | RSpec 2.14, 2.99, and 3.0 are now supported. 8 | -------------------------------------------------------------------------------- /Gemfile: -------------------------------------------------------------------------------- 1 | source 'https://rubygems.org' 2 | 3 | # Specify your gem's dependencies in ci_reporter_rspec.gemspec 4 | gemspec 5 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | Copyright (c) 2006-2014 Nick Sieger 2 | Copyright (c) 2014 The CI Reporter authors 3 | 4 | MIT License 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining 7 | a copy of this software and associated documentation files (the 8 | "Software"), to deal in the Software without restriction, including 9 | without limitation the rights to use, copy, modify, merge, publish, 10 | distribute, sublicense, and/or sell copies of the Software, and to 11 | permit persons to whom the Software is furnished to do so, subject to 12 | the following conditions: 13 | 14 | The above copyright notice and this permission notice shall be 15 | included in all copies or substantial portions of the Software. 16 | 17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 18 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 19 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 20 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 21 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 22 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 23 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 24 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # CI::Reporter::RSpec 2 | 3 | Connects [RSpec][rspec] to [CI::Reporter][ci], and then to your CI 4 | system. 5 | 6 | [![Gem Version](https://badge.fury.io/rb/ci_reporter_rspec.svg)](http://badge.fury.io/rb/ci_reporter_rspec) 7 | [![Build Status](https://travis-ci.org/ci-reporter/ci_reporter_rspec.svg?branch=master)](https://travis-ci.org/ci-reporter/ci_reporter_rspec) 8 | [![Dependency Status](https://gemnasium.com/ci-reporter/ci_reporter_rspec.svg)](https://gemnasium.com/ci-reporter/ci_reporter_rspec) 9 | [![Code Climate](https://codeclimate.com/github/ci-reporter/ci_reporter_rspec.png)](https://codeclimate.com/github/ci-reporter/ci_reporter_rspec) 10 | 11 | [rspec]: https://www.relishapp.com/rspec 12 | [ci]: https://github.com/ci-reporter/ci_reporter 13 | 14 | ## Supported versions 15 | 16 | The latest release of RSpec 2.14, 2.99 and 3 are supported. 17 | 18 | ## Installation 19 | 20 | Add this line to your application's Gemfile: 21 | 22 | ```ruby 23 | gem 'ci_reporter_rspec' 24 | ``` 25 | 26 | And then install it: 27 | 28 | ``` 29 | $ bundle 30 | ``` 31 | 32 | ## Usage 33 | 34 | Require the reporter in your Rakefile, and ensure that 35 | `ci:setup:rspec` is a dependency of your RSpec task: 36 | 37 | ```ruby 38 | require 'ci/reporter/rake/rspec' 39 | 40 | # ... 41 | # Rake code that creates a task called `:rspec` 42 | # ... 43 | 44 | task :rspec => 'ci:setup:rspec' 45 | ``` 46 | 47 | ### Advanced usage 48 | 49 | Refer to the shared [documentation][ci] for details on setting up 50 | CI::Reporter. 51 | 52 | ### `rspec-rails` 53 | 54 | If you use the [rspec-rails][rspec-rails] gem, you can follow the 55 | example above and use the predefined Rake target `:spec`. 56 | 57 | [rspec-rails]: https://www.relishapp.com/rspec/rspec-rails/docs 58 | 59 | ## Formatters 60 | 61 | CI::Reporter has separate Rake tasks for each built-in RSpec 62 | formatter. Depending upon which formatter you would like, call the 63 | corresponding task. 64 | 65 | | Formatter | Task | 66 | |--------------------|--------------------| 67 | | Progress (default) | ci:setup:rspec | 68 | | Base | ci:setup:rspecbase | 69 | | Documentation | ci:setup:rspecdoc | 70 | 71 | ## Contributing 72 | 73 | 1. Fork it ( https://github.com/ci-reporter/ci_reporter_rspec/fork ) 74 | 2. Create your feature branch (`git checkout -b my-new-feature`) 75 | 3. Add a failing test. 76 | 4. Commit your changes (`git commit -am 'Add some feature'`) 77 | 5. Ensure tests pass. 78 | 6. Push to the branch (`git push origin my-new-feature`) 79 | 7. Create a new Pull Request 80 | -------------------------------------------------------------------------------- /Rakefile: -------------------------------------------------------------------------------- 1 | require "bundler/gem_tasks" 2 | require 'ci/reporter/test_utils/rake' 3 | include CI::Reporter::TestUtils::Rake 4 | 5 | namespace :generate do 6 | task :clean do 7 | rm_rf "acceptance/reports" 8 | end 9 | 10 | task :rspec do 11 | rspec = "#{Gem.loaded_specs['rspec-core'].gem_dir}/exe/rspec" 12 | run_ruby_acceptance "-S #{rspec} --require ci/reporter/rake/rspec_loader --format CI::Reporter::RSpecFormatter acceptance/rspec_example_spec.rb" 13 | end 14 | 15 | task :all => [:clean, :rspec] 16 | end 17 | 18 | task :acceptance => "generate:all" 19 | 20 | require 'rspec/core/rake_task' 21 | RSpec::Core::RakeTask.new(:acceptance_spec) do |t| 22 | t.pattern = FileList['acceptance/verification_spec.rb'] 23 | t.rspec_opts = "--color" 24 | end 25 | task :acceptance => :acceptance_spec 26 | 27 | RSpec::Core::RakeTask.new(:unit_spec) do |t| 28 | t.pattern = FileList['spec'] 29 | t.rspec_opts = "--color" 30 | end 31 | 32 | task :default => [:unit_spec, :acceptance] 33 | -------------------------------------------------------------------------------- /acceptance/.gitignore: -------------------------------------------------------------------------------- 1 | reports/ 2 | -------------------------------------------------------------------------------- /acceptance/rspec_example_spec.rb: -------------------------------------------------------------------------------- 1 | RSpec.configure do |config| 2 | config.expect_with :rspec do |c| 3 | c.syntax = [:should, :expect] 4 | end 5 | end 6 | 7 | describe "a passing example" do 8 | it "passes" do 9 | true.should be true 10 | end 11 | end 12 | 13 | describe "a failing example" do 14 | it "fails" do 15 | true.should be false 16 | end 17 | end 18 | 19 | describe "an errored example" do 20 | it "errors" do 21 | raise "What happened?" 22 | end 23 | end 24 | 25 | describe "a pending example" do 26 | it "is not run" 27 | end 28 | 29 | describe "a failure in a before block" do 30 | before do 31 | true.should be false 32 | end 33 | 34 | it "doesn't matter" do 35 | true.should be true 36 | end 37 | end 38 | 39 | describe "outer context" do 40 | it "passes" do 41 | true.should be true 42 | end 43 | 44 | describe "inner context" do 45 | it "passes" do 46 | true.should be true 47 | end 48 | end 49 | end 50 | -------------------------------------------------------------------------------- /acceptance/verification_spec.rb: -------------------------------------------------------------------------------- 1 | require 'rexml/document' 2 | require 'ci/reporter/test_utils/accessor' 3 | require 'ci/reporter/test_utils/shared_examples' 4 | begin 5 | require 'rspec/collection_matchers' 6 | rescue LoadError 7 | # This gem doesn't support all versions of RSpec 8 | end 9 | 10 | REPORTS_DIR = File.dirname(__FILE__) + '/reports' 11 | 12 | describe "RSpec acceptance" do 13 | include CI::Reporter::TestUtils::SharedExamples 14 | Accessor = CI::Reporter::TestUtils::Accessor 15 | 16 | let(:passing_report_path) { File.join(REPORTS_DIR, 'SPEC-a-passing-example.xml') } 17 | let(:failing_report_path) { File.join(REPORTS_DIR, 'SPEC-a-failing-example.xml') } 18 | let(:errored_report_path) { File.join(REPORTS_DIR, 'SPEC-an-errored-example.xml') } 19 | let(:pending_report_path) { File.join(REPORTS_DIR, 'SPEC-a-pending-example.xml') } 20 | let(:failure_in_before_report_path) { File.join(REPORTS_DIR, 'SPEC-a-failure-in-a-before-block.xml') } 21 | let(:nested_outer_report_path) { File.join(REPORTS_DIR, 'SPEC-outer-context.xml') } 22 | let(:nested_inner_report_path) { File.join(REPORTS_DIR, 'SPEC-outer-context-inner-context.xml') } 23 | 24 | describe "the passing test" do 25 | subject(:result) { Accessor.new(load_xml_result(passing_report_path)) } 26 | 27 | it { should have(0).errors } 28 | it { should have(0).failures } 29 | it { should have(1).testcases } 30 | 31 | it_behaves_like "a report with consistent attribute counts" 32 | it_behaves_like "assertions are not tracked" 33 | it_behaves_like "nothing was output" 34 | end 35 | 36 | describe "the failing test" do 37 | subject(:result) { Accessor.new(load_xml_result(failing_report_path)) } 38 | 39 | it { should have(0).errors } 40 | it { should have(1).failures } 41 | it { should have(1).testcases } 42 | 43 | describe "the failure" do 44 | subject(:failure) { result.failures.first } 45 | it "indicates the type" do 46 | failure.type.should =~ /ExpectationNotMetError/ 47 | end 48 | end 49 | 50 | it_behaves_like "a report with consistent attribute counts" 51 | it_behaves_like "assertions are not tracked" 52 | it_behaves_like "nothing was output" 53 | end 54 | 55 | describe "the errored test" do 56 | subject(:result) { Accessor.new(load_xml_result(errored_report_path)) } 57 | 58 | it { should have(1).errors } 59 | it { should have(0).failures } 60 | it { should have(1).testcases } 61 | 62 | it_behaves_like "a report with consistent attribute counts" 63 | it_behaves_like "assertions are not tracked" 64 | it_behaves_like "nothing was output" 65 | end 66 | 67 | describe "the pending test" do 68 | subject(:result) { Accessor.new(load_xml_result(pending_report_path)) } 69 | 70 | it { should have(0).errors } 71 | it { should have(0).failures } 72 | it { should have(1).testcases } 73 | 74 | describe "the skipped count" do 75 | subject { result.skipped_count } 76 | it { should eql 1 } 77 | end 78 | 79 | it_behaves_like "a report with consistent attribute counts" 80 | it_behaves_like "assertions are not tracked" 81 | it_behaves_like "nothing was output" 82 | end 83 | 84 | describe "the test that fails in a before block" do 85 | subject(:result) { Accessor.new(load_xml_result(failure_in_before_report_path)) } 86 | 87 | it { should have(0).errors } 88 | it { should have(1).failures } 89 | it { should have(1).testcases } 90 | 91 | it_behaves_like "a report with consistent attribute counts" 92 | it_behaves_like "assertions are not tracked" 93 | it_behaves_like "nothing was output" 94 | end 95 | 96 | describe "the outer context" do 97 | subject(:result) { Accessor.new(load_xml_result(nested_outer_report_path)) } 98 | 99 | it { should have(0).errors } 100 | it { should have(0).failures } 101 | it { should have(1).testcases } 102 | 103 | it_behaves_like "a report with consistent attribute counts" 104 | it_behaves_like "assertions are not tracked" 105 | it_behaves_like "nothing was output" 106 | end 107 | 108 | describe "the inner context" do 109 | subject(:result) { Accessor.new(load_xml_result(nested_inner_report_path)) } 110 | 111 | it { should have(0).errors } 112 | it { should have(0).failures } 113 | it { should have(1).testcases } 114 | 115 | it_behaves_like "a report with consistent attribute counts" 116 | it_behaves_like "assertions are not tracked" 117 | it_behaves_like "nothing was output" 118 | end 119 | 120 | def load_xml_result(path) 121 | File.open(path) do |f| 122 | REXML::Document.new(f) 123 | end 124 | end 125 | end 126 | -------------------------------------------------------------------------------- /ci_reporter_rspec.gemspec: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | lib = File.expand_path('../lib', __FILE__) 3 | $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib) 4 | require 'ci/reporter/rspec/version' 5 | 6 | Gem::Specification.new do |spec| 7 | spec.name = "ci_reporter_rspec" 8 | spec.version = CI::Reporter::RSpec::VERSION 9 | spec.authors = ["Nick Sieger", "Jake Goulding"] 10 | spec.email = ["nick@nicksieger.com", "jake.goulding@gmail.com"] 11 | spec.summary = %q{Connects CI::Reporter to RSpec} 12 | spec.homepage = "https://github.com/ci-reporter/ci_reporter_rspec" 13 | spec.license = "MIT" 14 | 15 | spec.files = `git ls-files -z`.split("\x0") 16 | spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) } 17 | spec.test_files = spec.files.grep(%r{^(test|spec|features|acceptance)/}) 18 | spec.require_paths = ["lib"] 19 | 20 | spec.add_dependency "rspec", ">= 2.14", "< 4" 21 | spec.add_dependency "ci_reporter", "~> 2.0" 22 | 23 | spec.add_development_dependency "bundler", "~> 1.6" 24 | spec.add_development_dependency "rake" 25 | spec.add_development_dependency "ci_reporter_test_utils" 26 | spec.add_development_dependency "rspec-collection_matchers" 27 | end 28 | -------------------------------------------------------------------------------- /gemfiles/.gitignore: -------------------------------------------------------------------------------- 1 | Gemfile*lock 2 | -------------------------------------------------------------------------------- /gemfiles/Gemfile.2.14: -------------------------------------------------------------------------------- 1 | source 'https://rubygems.org' 2 | 3 | gem 'rake' 4 | gem 'rspec', '~> 2.14.0' 5 | gem 'ci_reporter_rspec', path: '..' 6 | 7 | group :test do 8 | gem 'ci_reporter_test_utils' 9 | end 10 | -------------------------------------------------------------------------------- /gemfiles/Gemfile.2.99: -------------------------------------------------------------------------------- 1 | source 'https://rubygems.org' 2 | 3 | gem 'rake' 4 | gem 'rspec', '~> 2.99.0' 5 | gem 'ci_reporter_rspec', path: '..' 6 | 7 | group :test do 8 | gem 'ci_reporter_test_utils' 9 | end 10 | -------------------------------------------------------------------------------- /lib/ci/reporter/rake/rspec.rb: -------------------------------------------------------------------------------- 1 | require 'ci/reporter/rake/utils' 2 | 3 | namespace :ci do 4 | namespace :setup do 5 | task :spec_report_cleanup do 6 | rm_rf ENV["CI_REPORTS"] || "spec/reports" 7 | end 8 | 9 | def setup_spec_opts(*extra_options) 10 | base_opts = [ 11 | "--require", CI::Reporter.maybe_quote_filename("#{File.dirname(__FILE__)}/rspec_loader.rb"), 12 | "--format", "CI::Reporter::RSpecFormatter" 13 | ] 14 | 15 | spec_opts = (base_opts + extra_options).join(" ") 16 | ENV["SPEC_OPTS"] = "#{ENV['SPEC_OPTS']} #{spec_opts}" 17 | end 18 | 19 | task :rspec => :spec_report_cleanup do 20 | setup_spec_opts("--format", "progress") 21 | end 22 | 23 | task :rspecdoc => :spec_report_cleanup do 24 | setup_spec_opts("--format", "documentation") 25 | end 26 | 27 | task :rspecbase => :spec_report_cleanup do 28 | setup_spec_opts 29 | end 30 | end 31 | end 32 | -------------------------------------------------------------------------------- /lib/ci/reporter/rake/rspec_loader.rb: -------------------------------------------------------------------------------- 1 | $: << File.dirname(__FILE__) + "/../../.." 2 | require 'ci/reporter/rspec' 3 | -------------------------------------------------------------------------------- /lib/ci/reporter/rspec.rb: -------------------------------------------------------------------------------- 1 | require 'ci/reporter/core' 2 | 3 | module CI::Reporter 4 | rspec_version = Gem::Version.new(::RSpec::Core::Version::STRING) 5 | rspec_3 = Gem::Version.new('3.0.0') 6 | RSPEC_3_AVAILABLE = rspec_version >= rspec_3 7 | 8 | if RSPEC_3_AVAILABLE 9 | require 'ci/reporter/rspec3/formatter' 10 | RSpecFormatter = CI::Reporter::RSpec3::Formatter 11 | else 12 | require 'ci/reporter/rspec2/formatter' 13 | RSpecFormatter = CI::Reporter::RSpec2::Formatter 14 | end 15 | end 16 | -------------------------------------------------------------------------------- /lib/ci/reporter/rspec/version.rb: -------------------------------------------------------------------------------- 1 | module CI 2 | module Reporter 3 | module RSpec 4 | VERSION = "1.0.0" 5 | end 6 | end 7 | end 8 | -------------------------------------------------------------------------------- /lib/ci/reporter/rspec2/failure.rb: -------------------------------------------------------------------------------- 1 | module CI::Reporter 2 | module RSpec2 3 | class Failure 4 | attr_reader :exception 5 | 6 | def initialize(example, formatter) 7 | @formatter = formatter 8 | @example = example 9 | if @example.respond_to?(:execution_result) 10 | @exception = @example.execution_result[:exception] || @example.execution_result[:exception_encountered] 11 | else 12 | @exception = @example.metadata[:execution_result][:exception] 13 | end 14 | end 15 | 16 | def name 17 | @exception.class.name 18 | end 19 | 20 | def message 21 | @exception.message 22 | end 23 | 24 | def failure? 25 | exception.is_a?(::RSpec::Expectations::ExpectationNotMetError) 26 | end 27 | 28 | def error? 29 | !failure? 30 | end 31 | 32 | def location 33 | output = [] 34 | output.push "#{exception.class.name << ":"}" unless exception.class.name =~ /RSpec/ 35 | output.push @exception.message 36 | 37 | [@formatter.format_backtrace(@exception.backtrace, @example)].flatten.each do |backtrace_info| 38 | backtrace_info.lines.each do |line| 39 | output.push " #{line}" 40 | end 41 | end 42 | output.join "\n" 43 | end 44 | end 45 | end 46 | end 47 | -------------------------------------------------------------------------------- /lib/ci/reporter/rspec2/formatter.rb: -------------------------------------------------------------------------------- 1 | require 'rspec/core/formatters/base_formatter' 2 | require 'ci/reporter/rspec2/failure' 3 | 4 | module CI::Reporter 5 | module RSpec2 6 | class Formatter < ::RSpec::Core::Formatters::BaseFormatter 7 | attr_accessor :report_manager 8 | def initialize(*args) 9 | @report_manager = ReportManager.new("spec") 10 | @suite = nil 11 | end 12 | 13 | def example_group_started(example_group) 14 | new_suite(description_for(example_group)) 15 | end 16 | 17 | def example_started(name_or_example) 18 | spec = TestCase.new 19 | @suite.testcases << spec 20 | spec.start 21 | end 22 | 23 | def example_failed(name_or_example, *rest) 24 | # In case we fail in before(:all) 25 | example_started(name_or_example) if @suite.testcases.empty? 26 | 27 | failure = Failure.new(name_or_example, self) 28 | 29 | spec = @suite.testcases.last 30 | spec.finish 31 | spec.name = description_for(name_or_example) 32 | spec.failures << failure 33 | end 34 | 35 | def example_passed(name_or_example) 36 | spec = @suite.testcases.last 37 | spec.finish 38 | spec.name = description_for(name_or_example) 39 | end 40 | 41 | def example_pending(*args) 42 | name = description_for(args[0]) 43 | spec = @suite.testcases.last 44 | spec.finish 45 | spec.name = "#{name} (PENDING)" 46 | spec.skipped = true 47 | end 48 | 49 | def dump_summary(*args) 50 | write_report 51 | end 52 | 53 | private 54 | def description_for(name_or_example) 55 | if name_or_example.respond_to?(:full_description) 56 | name_or_example.full_description 57 | elsif name_or_example.respond_to?(:metadata) 58 | name_or_example.metadata[:example_group][:full_description] 59 | elsif name_or_example.respond_to?(:description) 60 | name_or_example.description 61 | else 62 | "UNKNOWN" 63 | end 64 | end 65 | 66 | def write_report 67 | if @suite 68 | @suite.finish 69 | @report_manager.write_report(@suite) 70 | end 71 | end 72 | 73 | def new_suite(name) 74 | write_report if @suite 75 | @suite = TestSuite.new name 76 | @suite.start 77 | end 78 | end 79 | end 80 | end 81 | -------------------------------------------------------------------------------- /lib/ci/reporter/rspec3/failure.rb: -------------------------------------------------------------------------------- 1 | module CI::Reporter 2 | module RSpec3 3 | class Failure 4 | def initialize(example) 5 | @example = example 6 | end 7 | 8 | def name 9 | exception.class.name 10 | end 11 | 12 | def message 13 | exception.message 14 | end 15 | 16 | def failure? 17 | exception.is_a?(::RSpec::Expectations::ExpectationNotMetError) 18 | end 19 | 20 | def error? 21 | !failure? 22 | end 23 | 24 | def location 25 | output = [] 26 | output.push "#{name}:" unless name =~ /RSpec/ 27 | output.push message 28 | output.push @example.formatted_backtrace 29 | output.join "\n" 30 | end 31 | 32 | def exception 33 | @example.exception 34 | end 35 | end 36 | end 37 | end 38 | -------------------------------------------------------------------------------- /lib/ci/reporter/rspec3/formatter.rb: -------------------------------------------------------------------------------- 1 | require 'ci/reporter/core' 2 | require 'ci/reporter/rspec3/failure' 3 | 4 | module CI::Reporter 5 | module RSpec3 6 | class Formatter 7 | attr_accessor :report_manager 8 | 9 | def initialize(*args) 10 | @report_manager = ReportManager.new("spec") 11 | end 12 | 13 | def example_group_started(notification) 14 | new_suite(notification.group.metadata[:full_description]) 15 | end 16 | 17 | def example_started(notification) 18 | spec = TestCase.new 19 | @suite.testcases << spec 20 | spec.start 21 | end 22 | 23 | def example_failed(notification) 24 | # In case we fail in before(:all) 25 | example_started(nil) if @suite.testcases.empty? 26 | 27 | failure = Failure.new(notification) 28 | 29 | current_spec.finish 30 | current_spec.name = notification.example.full_description 31 | current_spec.failures << failure 32 | end 33 | 34 | def example_passed(notification) 35 | current_spec.finish 36 | current_spec.name = notification.example.full_description 37 | end 38 | 39 | def example_pending(notification) 40 | current_spec.finish 41 | current_spec.name = "#{notification.example.full_description} (PENDING)" 42 | current_spec.skipped = true 43 | end 44 | 45 | def stop(notification) 46 | write_report 47 | end 48 | 49 | private 50 | 51 | def current_spec 52 | @suite.testcases.last 53 | end 54 | 55 | def write_report 56 | return unless @suite 57 | @suite.finish 58 | @report_manager.write_report(@suite) 59 | end 60 | 61 | def new_suite(name) 62 | write_report 63 | @suite = TestSuite.new(name) 64 | @suite.start 65 | end 66 | end 67 | 68 | ::RSpec::Core::Formatters.register Formatter, 69 | :example_group_started, 70 | :example_started, 71 | :example_passed, 72 | :example_failed, 73 | :example_pending, 74 | :stop 75 | end 76 | end 77 | -------------------------------------------------------------------------------- /spec/ci/reporter/rake/rake_tasks_spec.rb: -------------------------------------------------------------------------------- 1 | require File.dirname(__FILE__) + "/../../../spec_helper.rb" 2 | require 'rake' 3 | require 'ci/reporter/test_utils/unit' 4 | 5 | describe "Rake tasks" do 6 | include CI::Reporter::TestUtils::Unit 7 | 8 | let (:rake) { Rake::Application.new } 9 | 10 | before(:each) do 11 | Rake.application = rake 12 | load CI_REPORTER_LIB + '/ci/reporter/rake/rspec.rb' 13 | save_env "CI_REPORTS" 14 | save_env "SPEC_OPTS" 15 | ENV["CI_REPORTS"] = "some-bogus-nonexistent-directory-that-wont-fail-rm_rf" 16 | end 17 | 18 | after(:each) do 19 | restore_env "SPEC_OPTS" 20 | restore_env "CI_REPORTS" 21 | Rake.application = nil 22 | end 23 | 24 | subject(:spec_opts) { ENV["SPEC_OPTS"] } 25 | 26 | context "ci:setup:rspec" do 27 | before do 28 | rake["ci:setup:rspec"].invoke 29 | end 30 | 31 | it { should match(/--require\s+\S+rspec_loader/) } 32 | it { should match(/--format\s+CI::Reporter::RSpecFormatter\b/) } 33 | it { should match(/--format\s+progress/) } 34 | end 35 | 36 | context "ci:setup:rspecdoc" do 37 | before do 38 | rake["ci:setup:rspecdoc"].invoke 39 | end 40 | 41 | it { should match(/--require\s+\S+rspec_loader/) } 42 | it { should match(/--format\s+CI::Reporter::RSpecFormatter\b/) } 43 | it { should match(/--format\s+documentation/) } 44 | end 45 | 46 | context "ci:setup:rspecbase" do 47 | before do 48 | rake["ci:setup:rspecbase"].invoke 49 | end 50 | 51 | it { should match(/--require\s+\S+rspec_loader/) } 52 | it { should match(/--format\s+CI::Reporter::RSpecFormatter\b/) } 53 | end 54 | 55 | context "with existing options" do 56 | it "appends new options" do 57 | ENV["SPEC_OPTS"] = "previous-value".freeze 58 | rake["ci:setup:rspec"].invoke 59 | spec_opts.should match(/previous-value.*CI::Reporter::RSpecFormatter\b/) 60 | end 61 | end 62 | end 63 | -------------------------------------------------------------------------------- /spec/ci/reporter/rspec2/failure_spec.rb: -------------------------------------------------------------------------------- 1 | require File.dirname(__FILE__) + "/../../../spec_helper.rb" 2 | require File.dirname(__FILE__) + "/../../../support/rspec2" 3 | require 'ci/reporter/rspec' 4 | require 'ci/reporter/rspec2/failure' 5 | 6 | module CI::Reporter::RSpec2 7 | describe Failure do 8 | include RSpec2Helpers 9 | 10 | before(:each) do 11 | skip "RSpec 3 present, skipping RSpec 2 tests" if CI::Reporter::RSPEC_3_AVAILABLE 12 | end 13 | 14 | before(:each) do 15 | @formatter = Formatter.new 16 | @rspec20_example = double('RSpec2.0 Example', 17 | :execution_result => {:exception_encountered => StandardError.new('rspec2.0 ftw')}, 18 | :metadata => {}) 19 | 20 | @rspec22_example = rspec2_failing_example('rspec2.2 ftw') 21 | end 22 | 23 | it 'should handle rspec (< 2.2) execution results' do 24 | failure = Failure.new(@rspec20_example, @formatter) 25 | failure.name.should_not be_nil 26 | failure.message.should == 'rspec2.0 ftw' 27 | failure.location.should_not be_nil 28 | end 29 | it 'should handle rspec (>= 2.2) execution results' do 30 | failure = Failure.new(@rspec22_example, @formatter) 31 | failure.name.should_not be_nil 32 | failure.message.should == 'rspec2.2 ftw' 33 | failure.location.should_not be_nil 34 | end 35 | end 36 | end 37 | -------------------------------------------------------------------------------- /spec/ci/reporter/rspec2/formatter_spec.rb: -------------------------------------------------------------------------------- 1 | require File.dirname(__FILE__) + "/../../../spec_helper.rb" 2 | require File.dirname(__FILE__) + "/../../../support/rspec2" 3 | require 'ci/reporter/rspec' 4 | require 'ci/reporter/rspec2/formatter' 5 | require 'stringio' 6 | 7 | module CI::Reporter::RSpec2 8 | describe Formatter do 9 | include RSpec2Helpers 10 | 11 | before(:each) do 12 | skip "RSpec 3 present, skipping RSpec 2 tests" if CI::Reporter::RSPEC_3_AVAILABLE 13 | end 14 | 15 | before(:each) do 16 | @error = double("error") 17 | @error.stub(:expectation_not_met?).and_return(false) 18 | @error.stub(:pending_fixed?).and_return(false) 19 | @error.stub(:exception).and_return(StandardError.new) 20 | @report_mgr = double("report manager") 21 | @options = double("options") 22 | @args = [@options, StringIO.new("")] 23 | @fmt = Formatter.new *@args 24 | @fmt.report_manager = @report_mgr 25 | end 26 | 27 | it "should create a test suite with one success, one failure, and one pending" do 28 | @report_mgr.should_receive(:write_report) do |suite| 29 | suite.testcases.length.should == 3 30 | suite.testcases[0].should_not be_failure 31 | suite.testcases[0].should_not be_error 32 | suite.testcases[1].should be_error 33 | suite.testcases[2].name.should =~ /\(PENDING\)/ 34 | end 35 | 36 | example_group = double "example group" 37 | example_group.stub(:description).and_return "A context" 38 | 39 | @fmt.start(3) 40 | @fmt.example_group_started(example_group) 41 | @fmt.example_started("should pass") 42 | @fmt.example_passed("should pass") 43 | @fmt.example_started("should fail") 44 | @fmt.example_failed(rspec2_failing_example("should fail"), 1, @error) 45 | @fmt.example_started("should be pending") 46 | @fmt.example_pending("A context", "should be pending", "Not Yet Implemented") 47 | @fmt.start_dump 48 | @fmt.dump_summary(0.1, 3, 1, 1) 49 | @fmt.dump_pending 50 | @fmt.close 51 | end 52 | 53 | it "should use the example #description method when available" do 54 | group = double "example group" 55 | group.stub(:description).and_return "group description" 56 | example = double "example" 57 | example.stub(:description).and_return "should do something" 58 | 59 | @report_mgr.should_receive(:write_report) do |suite| 60 | suite.testcases.last.name.should == "should do something" 61 | end 62 | 63 | @fmt.start(2) 64 | @fmt.example_group_started(group) 65 | @fmt.example_started(example) 66 | @fmt.example_passed(example) 67 | @fmt.dump_summary(0.1, 1, 0, 0) 68 | end 69 | 70 | it "should create a test suite with failure in before(:all)" do 71 | example_group = double "example group" 72 | example_group.stub(:description).and_return "A context" 73 | 74 | @report_mgr.should_receive(:write_report) 75 | 76 | @fmt.start(2) 77 | @fmt.example_group_started(example_group) 78 | @fmt.example_failed(rspec2_failing_example("should fail"), 1, @error) 79 | @fmt.dump_summary(0.1, 1, 0, 0) 80 | end 81 | end 82 | end 83 | -------------------------------------------------------------------------------- /spec/spec_helper.rb: -------------------------------------------------------------------------------- 1 | require 'rubygems' 2 | begin 3 | require 'rspec' 4 | rescue LoadError 5 | require 'spec' 6 | end 7 | 8 | require 'rspec/autorun' if $0 =~ /rcov$/ 9 | 10 | unless defined?(CI_REPORTER_LIB) 11 | CI_REPORTER_LIB = File.expand_path(File.dirname(__FILE__) + "/../lib") 12 | $: << CI_REPORTER_LIB 13 | end 14 | 15 | require 'ci/reporter/core' 16 | 17 | REPORTS_DIR = File.dirname(__FILE__) + "/reports" unless defined?(REPORTS_DIR) 18 | -------------------------------------------------------------------------------- /spec/support/rspec2.rb: -------------------------------------------------------------------------------- 1 | module RSpec2Helpers 2 | def rspec2_failing_example(exception_text) 3 | double('RSpec2.2 Example', 4 | :execution_result => { 5 | :exception => StandardError.new(exception_text) 6 | }, 7 | :metadata => { 8 | :example_group => { 9 | :full_description => "description" 10 | } 11 | }) 12 | end 13 | end 14 | --------------------------------------------------------------------------------