├── .gitignore ├── Gemfile ├── Gemfile.lock ├── README.md ├── allure-rspec.gemspec ├── lib ├── allure-rspec.rb └── allure-rspec │ ├── adaptor.rb │ ├── dsl.rb │ ├── formatter.rb │ ├── hooks.rb │ └── version.rb ├── logo.png └── spec ├── another_spec.rb ├── extend_steps_spec.rb ├── hooks_spec.rb ├── issue51_spec.rb ├── nometavalue_spec.rb ├── shared_example_spec.rb └── spec_helper.rb /.gitignore: -------------------------------------------------------------------------------- 1 | *.class 2 | 3 | # Package Files # 4 | *.jar 5 | *.war 6 | *.ear 7 | *.gem 8 | 9 | allure-report 10 | target 11 | allure 12 | .idea 13 | *.iml 14 | *.ipr 15 | *.iws 16 | -------------------------------------------------------------------------------- /Gemfile: -------------------------------------------------------------------------------- 1 | source 'https://rubygems.org' 2 | 3 | gemspec 4 | -------------------------------------------------------------------------------- /Gemfile.lock: -------------------------------------------------------------------------------- 1 | PATH 2 | remote: . 3 | specs: 4 | allure-rspec (0.8.0) 5 | allure-ruby-adaptor-api (= 0.7.0) 6 | rspec (~> 3.5) 7 | 8 | GEM 9 | remote: https://rubygems.org/ 10 | specs: 11 | allure-ruby-adaptor-api (0.7.0) 12 | mimemagic 13 | nokogiri (~> 1.7) 14 | uuid 15 | diff-lcs (1.2.5) 16 | macaddr (1.7.1) 17 | systemu (~> 2.6.2) 18 | mimemagic (0.3.2) 19 | mini_portile2 (2.1.0) 20 | nokogiri (1.7.0) 21 | mini_portile2 (~> 2.1.0) 22 | rake (10.4.2) 23 | rspec (3.5.0) 24 | rspec-core (~> 3.5.0) 25 | rspec-expectations (~> 3.5.0) 26 | rspec-mocks (~> 3.5.0) 27 | rspec-core (3.5.4) 28 | rspec-support (~> 3.5.0) 29 | rspec-expectations (3.5.0) 30 | diff-lcs (>= 1.2.0, < 2.0) 31 | rspec-support (~> 3.5.0) 32 | rspec-mocks (3.5.0) 33 | diff-lcs (>= 1.2.0, < 2.0) 34 | rspec-support (~> 3.5.0) 35 | rspec-support (3.5.0) 36 | systemu (2.6.5) 37 | uuid (2.3.8) 38 | macaddr (~> 1.0) 39 | 40 | PLATFORMS 41 | ruby 42 | 43 | DEPENDENCIES 44 | allure-rspec! 45 | bundler 46 | rake 47 | 48 | BUNDLED WITH 49 | 1.13.7 50 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # [DEPRECATED] 2 | ## Please follow https://github.com/allure-framework/allure-ruby 3 | Allure RSpec Adaptor 4 | ===================== 5 | 6 | [![Gem Version](https://badge.fury.io/rb/allure-rspec.svg)](http://badge.fury.io/rb/allure-rspec) 7 | 8 | Adaptor to use the Allure framework along with the RSpec. See [an example](https://github.com/allure-examples/allure-rspec-example) project to take a quick tour. 9 | 10 | ## What's new 11 | 12 | See the [releases](https://github.com/allure-framework/allure-rspec/releases) tab. 13 | 14 | 15 | ## Setup 16 | 17 | Add the dependency to your Gemfile. Choose the version carefully: 18 | * 0.5.x - for RSpec2. 19 | * <= 0.6.7 - for RSpec < 3.2. 20 | * >= 0.6.9 - for RSpec >= 3.2. 21 | 22 | ```ruby 23 | gem 'allure-rspec' 24 | ``` 25 | 26 | And then include it in your spec_helper.rb: 27 | 28 | ```ruby 29 | require 'allure-rspec' 30 | 31 | RSpec.configure do |c| 32 | c.include AllureRSpec::Adaptor 33 | end 34 | ``` 35 | 36 | ## Advanced options 37 | 38 | You can specify the directory where the Allure test results will appear. By default it would be 'gen/allure-results' 39 | within your current directory. 40 | 41 | ```ruby 42 | AllureRSpec.configure do |c| 43 | c.output_dir = "/whatever/you/like" # default: gen/allure-results 44 | c.clean_dir = false # clean the output directory first? (default: true) 45 | c.logging_level = Logger::DEBUG # logging level (default: DEBUG) 46 | end 47 | ``` 48 | 49 | ## Usage examples 50 | 51 | ```ruby 52 | describe MySpec, :feature => "Some feature", :severity => :normal do 53 | 54 | before(:step) do |s| 55 | puts "Before step #{s.current_step}" 56 | end 57 | 58 | it "should be critical", :story => "First story", :severity => :critical, :testId => 99 do 59 | "string".should == "string" 60 | end 61 | 62 | it "should be steps enabled", :story => ["First story", "Second story"], :testId => 31 do |e| 63 | 64 | e.step "step1" do |s| 65 | s.attach_file "screenshot1", take_screenshot_as_file 66 | end 67 | 68 | e.step "step2" do 69 | 5.should be > 0 70 | end 71 | 72 | e.step "step3" do 73 | 0.should == 0 74 | end 75 | 76 | e.attach_file "screenshot2", take_screenshot_as_file 77 | end 78 | end 79 | ``` 80 | -------------------------------------------------------------------------------- /allure-rspec.gemspec: -------------------------------------------------------------------------------- 1 | # -*- encoding: utf-8 -*- 2 | $LOAD_PATH.unshift File.expand_path("../lib", __FILE__) 3 | require "allure-rspec/version" 4 | 5 | Gem::Specification.new do |s| 6 | s.name = 'allure-rspec' 7 | s.version = AllureRSpec::Version::STRING 8 | s.platform = Gem::Platform::RUBY 9 | s.authors = ['Ilya Sadykov'] 10 | s.email = ['smecsia@yandex-team.ru'] 11 | s.description = %q{Adaptor to use Allure framework along with the RSpec 2} 12 | s.summary = "allure-rspec-#{AllureRSpec::Version::STRING}" 13 | s.homepage = 'http://allure.qatools.ru' 14 | s.license = 'Apache-2.0' 15 | 16 | s.files = `git ls-files`.split("\n") 17 | s.test_files = `git ls-files -- {spec,features}/*`.split("\n") 18 | s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) } 19 | s.require_paths = ['lib'] 20 | 21 | s.add_dependency 'rspec', '~> 3.5' 22 | s.add_dependency 'allure-ruby-adaptor-api', '0.7.0' 23 | 24 | s.add_development_dependency 'bundler' 25 | s.add_development_dependency 'rake' 26 | end 27 | -------------------------------------------------------------------------------- /lib/allure-rspec.rb: -------------------------------------------------------------------------------- 1 | require 'allure-ruby-adaptor-api' 2 | require 'allure-rspec/version' 3 | require 'allure-rspec/formatter' 4 | require 'allure-rspec/adaptor' 5 | require 'allure-rspec/dsl' 6 | require 'allure-rspec/hooks' 7 | 8 | module AllureRSpec 9 | module Config 10 | class << self 11 | attr_accessor :output_dir 12 | attr_accessor :clean_dir 13 | attr_accessor :logging_level 14 | 15 | DEFAULT_OUTPUT_DIR = 'gen/allure-results' 16 | DEFAULT_LOGGING_LEVEL = Logger::DEBUG 17 | 18 | def output_dir 19 | @output_dir || DEFAULT_OUTPUT_DIR 20 | end 21 | 22 | def clean_dir? 23 | @clean_dir.nil? ? true : @clean_dir 24 | end 25 | 26 | def logging_level 27 | @logging_level || DEFAULT_LOGGING_LEVEL 28 | end 29 | end 30 | end 31 | 32 | class Context 33 | attr_accessor :rspec 34 | 35 | def rspec 36 | @rspec 37 | end 38 | end 39 | 40 | class << self 41 | def context 42 | @context ||= Context.new 43 | end 44 | end 45 | 46 | class << self 47 | def configure(&block) 48 | yield Config 49 | AllureRubyAdaptorApi.configure { |c| 50 | c.output_dir = Config.output_dir 51 | c.logging_level = Config.logging_level 52 | } 53 | end 54 | end 55 | 56 | end 57 | -------------------------------------------------------------------------------- /lib/allure-rspec/adaptor.rb: -------------------------------------------------------------------------------- 1 | module AllureRSpec 2 | module Adaptor 3 | def self.included(base) 4 | AllureRSpec.context.rspec = base 5 | base.send :include, AllureRSpec::DSL 6 | if RSpec::Core::Formatters::Loader.formatters.keys.find_all { |f| f == AllureRSpec::Formatter }.empty? 7 | RSpec::Core::Formatters.register AllureRSpec::Formatter, *AllureRSpec::Formatter::NOTIFICATIONS 8 | RSpec.configuration.add_formatter(AllureRSpec::Formatter) 9 | end 10 | RSpec::Core::ExampleGroup.send :include, AllureRSpec::Hooks 11 | RSpec::Core::Example.send :include, AllureRSpec::DSL::Example 12 | end 13 | end 14 | end 15 | 16 | -------------------------------------------------------------------------------- /lib/allure-rspec/dsl.rb: -------------------------------------------------------------------------------- 1 | require 'digest' 2 | require 'mimemagic' 3 | module AllureRSpec 4 | module DSL 5 | module Example 6 | 7 | def current_step 8 | if defined? @@__current_step 9 | @@__current_step 10 | else 11 | nil 12 | end 13 | end 14 | 15 | def step(step, &block) 16 | suite = __description(metadata[:example_group]) 17 | test = __description(metadata) 18 | begin 19 | AllureRubyAdaptorApi::Builder.start_step(suite, test, step) 20 | __with_step step, &block 21 | AllureRubyAdaptorApi::Builder.stop_step(suite, test, step) 22 | rescue Exception => e 23 | AllureRubyAdaptorApi::Builder.stop_step(suite, test, step, :failed) 24 | raise e 25 | end 26 | end 27 | 28 | 29 | def attach_file(title, file, opts = {}) 30 | suite = __description(metadata[:example_group]) 31 | test = __description(metadata) 32 | step = current_step 33 | AllureRubyAdaptorApi::Builder.add_attachment suite, test, opts.merge(:title => title, :file => file, :step => step) 34 | end 35 | 36 | private 37 | 38 | def __description(data) 39 | data[:full_description] || data[:description] 40 | end 41 | 42 | def __mutex 43 | @@__mutex ||= Mutex.new 44 | end 45 | 46 | def __with_step(step, &block) 47 | __mutex.synchronize do 48 | begin 49 | @@__current_step = step 50 | AllureRSpec.context.rspec.hooks.send :run, :before, :step, self 51 | yield self 52 | ensure 53 | AllureRSpec.context.rspec.hooks.send :run, :after, :step, self 54 | @@__current_step = nil 55 | end 56 | end 57 | end 58 | end 59 | end 60 | end 61 | 62 | -------------------------------------------------------------------------------- /lib/allure-rspec/formatter.rb: -------------------------------------------------------------------------------- 1 | require 'rspec/core' unless defined?(RSpec::Core) 2 | require 'rspec/core/formatters/base_formatter' unless defined?(RSpec::Core::Formatters::BaseFormatter) 3 | require 'fileutils' 4 | 5 | module AllureRSpec 6 | 7 | class Formatter < RSpec::Core::Formatters::BaseFormatter 8 | 9 | NOTIFICATIONS = [:example_group_started, :example_group_finished, :example_started, 10 | :example_failed, :example_passed, :example_pending, :start, :stop] 11 | ALLOWED_LABELS = [:feature, :story, :severity, :language, :framework, :issue, :testId, :host, :thread] 12 | 13 | def example_failed(notification) 14 | res = notification.example.execution_result 15 | status = res.exception.is_a?(RSpec::Expectations::ExpectationNotMetError) ? :failed : :broken 16 | stop_test(notification.example, :exception => res.exception, :status => status) 17 | end 18 | 19 | def example_group_finished(notification) 20 | AllureRubyAdaptorApi::Builder.stop_suite(description(notification.group).to_s) 21 | end 22 | 23 | def example_group_started(notification) 24 | AllureRubyAdaptorApi::Builder.start_suite(description(notification.group).to_s, labels(notification)) 25 | end 26 | 27 | def example_passed(notification) 28 | stop_test(notification.example) 29 | end 30 | 31 | def example_pending(notification) 32 | stop_test(notification.example) 33 | end 34 | 35 | def example_started(notification) 36 | suite = description(notification.example.example_group).to_s 37 | test = description(notification.example).to_s 38 | AllureRubyAdaptorApi::Builder.start_test(suite, test, labels(notification)) 39 | end 40 | 41 | def start(example_count) 42 | dir = Pathname.new(AllureRSpec::Config.output_dir) 43 | if AllureRSpec::Config.clean_dir? 44 | puts "Cleaning output directory '#{dir}'..." 45 | FileUtils.rm_rf(dir) 46 | end 47 | FileUtils.mkdir_p(dir) 48 | end 49 | 50 | def stop(notify) 51 | AllureRubyAdaptorApi::Builder.build! 52 | end 53 | 54 | private 55 | 56 | def description(data, attr = :full_description) 57 | ((((data.respond_to?(attr)) ? 58 | data.send(attr) : data.metadata[attr]) || 59 | description(data, :description)) || '').strip 60 | end 61 | 62 | def stop_test(example, opts = {}) 63 | res = example.execution_result 64 | AllureRubyAdaptorApi::Builder.stop_test( 65 | description(example.example_group).to_s, 66 | (example.metadata[:description_args].size== 0) ? description(example.example_group) : description(example).to_s, 67 | { 68 | :status => res.status, 69 | :finished_at => res.finished_at, 70 | :started_at => res.started_at 71 | }.merge(opts) 72 | ) 73 | end 74 | 75 | def metadata(example_or_group) 76 | group?(example_or_group) ? 77 | example_or_group.group.metadata : 78 | example_or_group.example.metadata 79 | end 80 | 81 | def group?(example_or_group) 82 | (example_or_group.respond_to? :group) 83 | end 84 | 85 | def labels(example_or_group) 86 | labels = ALLOWED_LABELS.map { |label| [label, metadata(example_or_group)[label]] }. 87 | find_all { |value| !value[1].nil? }. 88 | inject({}) { |res, value| res.merge(value[0] => value[1]) } 89 | detect_feature_story(labels, example_or_group) 90 | labels 91 | end 92 | 93 | def method_or_key(metadata, key) 94 | metadata.respond_to?(key) ? metadata.send(key) : metadata[key] 95 | end 96 | 97 | def detect_feature_story(labels, example_or_group) 98 | metadata = metadata(example_or_group) 99 | is_group = group?(example_or_group) 100 | parent = (method_or_key(metadata, :parent_example_group)) 101 | if labels[:feature] === true 102 | description = (!is_group && parent) ? method_or_key(parent, :description) : method_or_key(metadata, :description) 103 | labels[:feature] = description 104 | if labels[:story] === true 105 | if parent 106 | grandparent = parent && method_or_key(parent, :parent_example_group) 107 | labels[:feature] = (!is_group && grandparent) ? method_or_key(grandparent, :description) : 108 | method_or_key(parent, :description) 109 | end 110 | labels[:story] = description 111 | end 112 | end 113 | labels 114 | end 115 | 116 | end 117 | end 118 | -------------------------------------------------------------------------------- /lib/allure-rspec/hooks.rb: -------------------------------------------------------------------------------- 1 | module AllureRSpec 2 | module Hooks 3 | 4 | def self.included(cls) 5 | cls.extend OverrideHooksMethods 6 | end 7 | 8 | module OverrideHooksMethods 9 | include RSpec::Core::Hooks 10 | 11 | alias_method :old_hooks, :hooks 12 | 13 | def hooks 14 | @__hooks ||= OverridenHookCollections.new(old_hooks) 15 | end 16 | 17 | private 18 | 19 | class OverridenHookCollections < RSpec::Core::Hooks::HookCollections 20 | def initialize(original) 21 | super(original.instance_eval("@owner"), original.instance_eval("@filterable_item_repo_class")) 22 | [:@before_example_hooks, :@after_example_hooks, :@before_context_hooks, :@after_context_hooks, :@around_example_hooks].each { |var| 23 | instance_variable_set(var, original.instance_eval("#{var}")) 24 | } 25 | @before_step_hooks = nil 26 | @after_step_hooks = nil 27 | end 28 | 29 | def run(position, scope, example_or_group) 30 | if scope == :step 31 | run_owned_hooks_for(position, scope, example_or_group) 32 | else 33 | super 34 | end 35 | end 36 | 37 | protected 38 | 39 | # TODO: This code is highly related to the RSpec internals. 40 | # It should be supported with every new RSpec version 41 | def matching_hooks_for(position, scope, example_or_group) 42 | if scope == :step 43 | repo = hooks_for(position, scope) || example_or_group.example_group.hooks.hooks_for(position, scope) 44 | metadata = case example_or_group 45 | when RSpec::Core::ExampleGroup then 46 | example_or_group.class.metadata 47 | else 48 | example_or_group.metadata 49 | end 50 | repo.nil? ? EMPTY_HOOK_ARRAY : repo.items_for(metadata) 51 | else 52 | super 53 | end 54 | end 55 | 56 | def hooks_for(position, scope) 57 | if scope == :step 58 | position == :before ? @before_step_hooks : @after_step_hooks 59 | else 60 | super 61 | end 62 | end 63 | 64 | def ensure_hooks_initialized_for(position, scope) 65 | if scope == :step 66 | if position == :before 67 | @before_step_hooks ||= @filterable_item_repo_class.new(:all?) 68 | else 69 | @after_step_hooks ||= @filterable_item_repo_class.new(:all?) 70 | end 71 | else 72 | super 73 | end 74 | end 75 | 76 | SCOPES = [:example, :context, :step] 77 | 78 | def known_scope?(scope) 79 | SCOPES.include?(scope) || super(scope) 80 | end 81 | 82 | end 83 | end 84 | end 85 | end 86 | 87 | -------------------------------------------------------------------------------- /lib/allure-rspec/version.rb: -------------------------------------------------------------------------------- 1 | module AllureRSpec # :nodoc: 2 | module Version # :nodoc: 3 | STRING = '0.8.0' 4 | end 5 | end 6 | -------------------------------------------------------------------------------- /logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/allure-framework/allure-rspec/929130b5cfb932c0cf3ec1b14499cae41d3c1524/logo.png -------------------------------------------------------------------------------- /spec/another_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | require 'tempfile' 3 | 4 | describe "Some another spec", :feature => ["Some Feature"], :severity => :normal do 5 | 6 | before(:suite) do 7 | puts "before suite" 8 | end 9 | 10 | after(:suite) do 11 | puts "after suite" 12 | end 13 | 14 | it "10 cannot be greater than 19", :story => ["Some story"], :testId => 10 do 15 | expect(10).to be > 19 16 | end 17 | 18 | it "4 must not be equal to 5", :testId => 20 do 19 | expect(5).to be eql(4) 20 | end 21 | end 22 | -------------------------------------------------------------------------------- /spec/extend_steps_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | require 'tempfile' 3 | 4 | describe AllureRSpec, :feature => "Basics" do 5 | 6 | before(:suite) do 7 | puts "before suite" 8 | end 9 | 10 | before(:context) do 11 | puts "before context" 12 | end 13 | 14 | before(:step) do |s| 15 | puts "before step #{s.current_step}" 16 | end 17 | 18 | before(:example) do 19 | puts "before example" 20 | end 21 | 22 | after(:step) do |s| 23 | puts "after step #{s.current_step}" 24 | end 25 | 26 | after(:example) do 27 | puts "after example" 28 | end 29 | 30 | after(:suite) do 31 | puts "after suite" 32 | end 33 | 34 | after(:context) do 35 | puts "after all" 36 | end 37 | 38 | it "should build", :story => "Main story" do |e| 39 | e.attach_file "test-file1", Tempfile.new("test") 40 | e.step "step1" do |step| 41 | step.attach_file "test-file2", Tempfile.new("test") 42 | end 43 | 44 | e.step "step2" do |step| 45 | step.attach_file "logo", File.new("logo.png") 46 | expect(5).to be > 1 47 | end 48 | 49 | e.step "step3" do 50 | expect(0).to eq(1) 51 | end 52 | end 53 | 54 | it "should be failed example" do 55 | fail_spec "Failure" 56 | end 57 | 58 | def fail_spec(desc) 59 | raise RSpec::Expectations::ExpectationNotMetError.new(desc) 60 | end 61 | 62 | it "should raise exception" do |e| 63 | 64 | e.step "step1" do 65 | expect(5).to be > 1 66 | end 67 | 68 | e.step "step2" do 69 | raise "Undesired exception" 70 | end 71 | 72 | end 73 | 74 | it "is a pending example" 75 | 76 | context "some context" do 77 | it do |e| 78 | expect("aa").to eq("aa") 79 | end 80 | 81 | it do |e| 82 | expect(5).to eq(6) 83 | end 84 | end 85 | 86 | end 87 | -------------------------------------------------------------------------------- /spec/hooks_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe 'When I test allure rspec' do 4 | before(:all) do 5 | puts 'Before all in foo spec' 6 | end 7 | 8 | it 'should do something' do 9 | puts 'In the test' 10 | expect(true).not_to be_nil 11 | end 12 | end -------------------------------------------------------------------------------- /spec/issue51_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe 'Example', feature: 'Some feature', story: 'some_story' do 4 | it 'first test case' do 5 | #pass 6 | end 7 | 8 | it 'second test case' do 9 | #pass 10 | end 11 | end 12 | -------------------------------------------------------------------------------- /spec/nometavalue_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | require 'tempfile' 3 | 4 | describe "Some feature", :feature do 5 | describe "Some story", :story do 6 | it "20 should be greater than 19", :story do 7 | expect(20).to be > 19 8 | end 9 | end 10 | 11 | end 12 | -------------------------------------------------------------------------------- /spec/shared_example_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | require "set" 3 | 4 | shared_examples_for "a collection" do 5 | let(:collection) { described_class.new([7, 2, 4]) } 6 | 7 | context "initialized with 3 items" do 8 | it "says it has three items" do 9 | expect(collection.size).to be 3 10 | end 11 | end 12 | 13 | describe "#include?" do 14 | context "with an an item that is in the collection" do 15 | it "returns true" do 16 | expect(collection.include?(7)).to be true 17 | end 18 | end 19 | 20 | context "with an an item that is not in the collection" do 21 | it "returns false" do 22 | expect(collection.include?(9)).to be false 23 | end 24 | end 25 | end 26 | end 27 | 28 | describe Array do 29 | it_behaves_like "a collection" 30 | end 31 | 32 | describe Set do 33 | it_behaves_like "a collection" 34 | end 35 | -------------------------------------------------------------------------------- /spec/spec_helper.rb: -------------------------------------------------------------------------------- 1 | require 'rspec' 2 | require 'allure-rspec' 3 | require 'nokogiri' 4 | 5 | RSpec.configure do |c| 6 | c.include AllureRSpec::Adaptor 7 | 8 | c.before(:suite) do 9 | puts 'Before Suite Spec helper' 10 | end 11 | 12 | c.before(:all) do 13 | puts 'Before all Spec helper' 14 | end 15 | end 16 | 17 | AllureRSpec.configure do |c| 18 | c.output_dir = "allure" 19 | end 20 | 21 | --------------------------------------------------------------------------------