├── .gitignore ├── CHANGELOG.md ├── Gemfile ├── LICENSE ├── README.md ├── Rakefile ├── lib └── rspec │ ├── example_steps.rb │ └── example_steps │ ├── documentation_formatter.rb │ ├── example_group.rb │ ├── notification.rb │ └── reporter.rb ├── rspec-example_steps.gemspec └── spec ├── example_steps_spec.rb ├── regression_spec.rb └── spec_helper.rb /.gitignore: -------------------------------------------------------------------------------- 1 | *.gem 2 | .bundle 3 | Gemfile.lock 4 | pkg/* 5 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | ## 3.1.1 4 | 5 | * Remove missing stuff of shared_steps feature 6 | 7 | ## 3.1.0 8 | 9 | * Remove shared_steps feature 10 | -------------------------------------------------------------------------------- /Gemfile: -------------------------------------------------------------------------------- 1 | source "http://rubygems.org" 2 | 3 | gemspec 4 | 5 | gem 'rspec', '3.0.0' 6 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2013 Railsware (www.railsware.com) 2 | 3 | MIT License 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining 6 | a copy of this software and associated documentation files (the 7 | "Software"), to deal in the Software without restriction, including 8 | without limitation the rights to use, copy, modify, merge, publish, 9 | distribute, sublicense, and/or sell copies of the Software, and to 10 | permit persons to whom the Software is furnished to do so, subject to 11 | the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be 14 | included in all copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 17 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 18 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 19 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 20 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 21 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 22 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 23 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## RSpec example steps 2 | 3 | Given/When/Then/And/But steps for RSpec examples 4 | 5 | ### Description 6 | 7 | This gem brings two major functionality to your `spec/features` 8 | 9 | * Verbosity for rspec documentation formatter. 10 | * Ability to comment or describe set of actions in example into some step. 11 | 12 | ### Installation 13 | 14 | * For rspec v2 use gem **v0.2.x** or rspec2 branch 15 | * For rspec v3 use gem **v3.x.x** or master branch 16 | 17 | ```ruby 18 | gem 'rspec-example_steps' 19 | ``` 20 | 21 | Add to `spec/spec_helper.rb` 22 | 23 | ```ruby 24 | require 'rspec/example_steps' 25 | ``` 26 | 27 | ### Example 28 | 29 | `spec/features/search_spec.rb` 30 | 31 | ```ruby 32 | context 'Searching' do 33 | Steps 'Result found' do 34 | Given 'I am on search page' do 35 | visit '/search' 36 | expect(page).to have_content('Search') 37 | end 38 | 39 | When 'I search something' do 40 | fill_in 'Search', with: 'John' 41 | click_button 'Go' 42 | end 43 | 44 | Then 'I should see result' do 45 | expect(page).to have_content('Result') 46 | end 47 | end 48 | end 49 | ``` 50 | 51 | ### Documentation formatting output: 52 | 53 | `rspec -fd spec/features/search_spec.rb` 54 | 55 |
56 | Searching
57 |   User succesfully replaces device
58 |     Given I am on search page
59 |     When I search something
60 |     Then I should see result
61 | 
62 | 63 | ### Pending steps 64 | 65 | Simular to Example :pending behavior: 66 | 67 | ```ruby 68 | Steps 'User login' do 69 | # just skip block 70 | When 'I go to login' 71 | 72 | # pass pending: true option 73 | Then 'I should see welcome', pending: true do 74 | ... 75 | end 76 | 77 | # pass pending: 'some pending message' 78 | Then 'I should see last login IP', pending: 'WIP' do 79 | ... 80 | end 81 | end 82 | ``` 83 | 84 | ## Authors 85 | 86 | * [Andriy Yanko](http://ayanko.github.io) 87 | 88 | ## License 89 | 90 | * Copyright (c) 2013 Railsware [www.railsware.com](http://www.railsware.com) 91 | * [MIT](www.opensource.org/licenses/MIT) 92 | 93 | ## Alternatives 94 | 95 | * [rspec-steps](https://github.com/LRDesign/rspec-steps) 96 | * [rspec-given](https://github.com/jimweirich/rspec-given) 97 | -------------------------------------------------------------------------------- /Rakefile: -------------------------------------------------------------------------------- 1 | require "bundler/gem_tasks" 2 | -------------------------------------------------------------------------------- /lib/rspec/example_steps.rb: -------------------------------------------------------------------------------- 1 | require 'rspec/core' 2 | require 'rspec/core/formatters' 3 | require 'rspec/core/formatters/console_codes' 4 | require 'rspec/core/formatters/documentation_formatter' 5 | require 'rspec/core/example_group' 6 | require 'rspec/core/reporter' 7 | 8 | require 'rspec/example_steps/documentation_formatter' 9 | require 'rspec/example_steps/example_group' 10 | require 'rspec/example_steps/notification' 11 | require 'rspec/example_steps/reporter' 12 | 13 | RSpec::Core::Formatters::DocumentationFormatter.send :include, RSpec::ExampleSteps::DocumentationFormatter 14 | RSpec::Core::ExampleGroup.send :include, RSpec::ExampleSteps::ExampleGroup 15 | RSpec::Core::Reporter.send :include, RSpec::ExampleSteps::Reporter 16 | 17 | RSpec::Core::ExampleGroup.define_example_method :Steps, with_steps: true 18 | 19 | if formatter = RSpec.world.reporter.find_registered_formatter(RSpec::Core::Formatters::DocumentationFormatter) 20 | RSpec.world.reporter.register_listener formatter, 21 | :example_started, :example_step_passed, :example_step_pending, :example_step_failed 22 | end 23 | -------------------------------------------------------------------------------- /lib/rspec/example_steps/documentation_formatter.rb: -------------------------------------------------------------------------------- 1 | module RSpec 2 | module ExampleSteps 3 | module DocumentationFormatter 4 | def self.included(base) 5 | base.class_eval do 6 | include InstanceMethods 7 | 8 | alias :example_started_without_steps :example_started 9 | alias :example_started :example_started_with_steps 10 | 11 | alias :example_passed_without_steps :example_passed 12 | alias :example_passed :example_passed_with_steps 13 | end 14 | end 15 | 16 | module InstanceMethods 17 | def example_started(notification) 18 | end 19 | 20 | def example_started_with_steps(notification) 21 | example_started_without_steps(notification) 22 | 23 | if notification.example.metadata[:with_steps] 24 | full_message = "#{current_indentation}#{notification.example.description}" 25 | output.puts Core::Formatters::ConsoleCodes.wrap(full_message, :default) 26 | end 27 | end 28 | 29 | def example_passed_with_steps(notification) 30 | example_passed_without_steps(notification) unless notification.example.metadata[:with_steps] 31 | end 32 | 33 | def example_step_passed(notification) 34 | full_message = "#{current_indentation} #{notification.type.to_s.capitalize} #{notification.message}" 35 | output.puts Core::Formatters::ConsoleCodes.wrap(full_message, :success) 36 | end 37 | 38 | def example_step_pending(notification) 39 | full_message = "#{current_indentation} #{notification.type.to_s.capitalize} #{notification.message}" 40 | 41 | if notification.options[:pending] && notification.options[:pending] != true 42 | full_message << " (PENDING: #{notification.options[:pending]})" 43 | else 44 | full_message << " (PENDING)" 45 | end 46 | 47 | output.puts Core::Formatters::ConsoleCodes.wrap(full_message, :pending) 48 | end 49 | 50 | def example_step_failed(notification) 51 | full_message = "#{current_indentation} #{notification.type.to_s.capitalize} #{notification.message} (FAILED)" 52 | output.puts Core::Formatters::ConsoleCodes.wrap(full_message, :failure) 53 | end 54 | end 55 | end 56 | end 57 | end 58 | -------------------------------------------------------------------------------- /lib/rspec/example_steps/example_group.rb: -------------------------------------------------------------------------------- 1 | module RSpec 2 | module ExampleSteps 3 | module ExampleGroup 4 | def Given(message, options = {}, &block) 5 | RSpec.world.reporter.process_example_step(self, :given, message, options, &block) 6 | end 7 | 8 | def When(message, options = {}, &block) 9 | RSpec.world.reporter.process_example_step(self, :when, message, options, &block) 10 | end 11 | 12 | def Then(message, options = {}, &block) 13 | RSpec.world.reporter.process_example_step(self, :then, message, options, &block) 14 | end 15 | 16 | def And(message, options = {}, &block) 17 | RSpec.world.reporter.process_example_step(self, :and, message, options, &block) 18 | end 19 | 20 | def But(message, options = {}, &block) 21 | RSpec.world.reporter.process_example_step(self, :but, message, options, &block) 22 | end 23 | end 24 | end 25 | end 26 | -------------------------------------------------------------------------------- /lib/rspec/example_steps/notification.rb: -------------------------------------------------------------------------------- 1 | module RSpec 2 | module ExampleSteps 3 | class Notification < Struct.new(:example, :type, :message, :options) 4 | end 5 | end 6 | end 7 | -------------------------------------------------------------------------------- /lib/rspec/example_steps/reporter.rb: -------------------------------------------------------------------------------- 1 | module RSpec 2 | module ExampleSteps 3 | module Reporter 4 | def process_example_step(example, type, message, options) 5 | example_step_started(self, type, message, options) 6 | 7 | if block_given? && !options[:pending] 8 | begin 9 | yield 10 | rescue Exception => e 11 | example_step_failed(self, type, message, options) 12 | raise e 13 | end 14 | example_step_passed(self, type, message, options) 15 | else 16 | example_step_pending(self, type, message, options) 17 | end 18 | end 19 | 20 | def example_step_started(example, type, message, options) 21 | notify :example_step_started, Notification.new(example, type, message, options) 22 | end 23 | 24 | def example_step_passed(example, type, message, options) 25 | notify :example_step_passed, Notification.new(example, type, message, options) 26 | end 27 | 28 | def example_step_pending(example, type, message, options) 29 | notify :example_step_pending, Notification.new(example, type, message, options) 30 | end 31 | 32 | def example_step_failed(example, type, message, options) 33 | notify :example_step_failed, Notification.new(example, type, message, options) 34 | end 35 | 36 | def registered_formatters 37 | @listeners.values.map(&:to_a).flatten.uniq 38 | end 39 | 40 | def find_registered_formatter(klass) 41 | registered_formatters.detect { |formatter| formatter.class == klass } 42 | end 43 | end 44 | end 45 | end 46 | -------------------------------------------------------------------------------- /rspec-example_steps.gemspec: -------------------------------------------------------------------------------- 1 | # -*- encoding: utf-8 -*- 2 | $:.push File.expand_path("../lib", __FILE__) 3 | 4 | Gem::Specification.new do |s| 5 | s.name = 'rspec-example_steps' 6 | s.version = '3.1.1' 7 | s.authors = ['Andriy Yanko'] 8 | s.email = ['andriy.yanko@gmail.com'] 9 | s.homepage = 'https://github.com/railsware/rspec-example_steps' 10 | s.summary = %q{Given/When/Then steps for RSpec examples} 11 | s.license = 'MIT' 12 | 13 | s.rubyforge_project = 'rspec_example_steps' 14 | 15 | s.files = `git ls-files`.split("\n") 16 | s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n") 17 | s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) } 18 | s.require_paths = ['lib'] 19 | 20 | s.add_runtime_dependency 'rspec-core', '>=3.0.0' 21 | end 22 | -------------------------------------------------------------------------------- /spec/example_steps_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe "example steps" do 4 | 5 | describe "Given/When/Then" do 6 | 7 | Steps "should execute blocks" do 8 | Given "thing" do 9 | @thing = "Given value" 10 | end 11 | 12 | When "action" do 13 | @action = "When value" 14 | end 15 | 16 | Then "result" do 17 | @result = "Then value" 18 | end 19 | 20 | And "and" do 21 | @and = "And value" 22 | end 23 | 24 | But "but" do 25 | @but = "But value" 26 | end 27 | 28 | expect(@thing).to eq("Given value") 29 | expect(@action).to eq("When value") 30 | expect(@result).to eq("Then value") 31 | expect(@and).to eq("And value") 32 | expect(@but).to eq("But value") 33 | end 34 | end 35 | 36 | 37 | describe "Steps without blocks" do 38 | Steps "they should be pending" do 39 | Given "step without block" 40 | Then "step without block" 41 | When "step without block" 42 | end 43 | end 44 | 45 | describe "Steps with :pending option" do 46 | Steps "they should be pending when :pending => true" do 47 | Given "step with :pending option", :pending => true do 48 | raise "Should not be evaluated" 49 | end 50 | 51 | When "step with :pending option", :pending => true do 52 | raise "Should not be evaluated" 53 | end 54 | 55 | Then "step with :pending option", :pending => true do 56 | raise "Should not be evaluated" 57 | end 58 | 59 | And "and step with :pending option", :pending => true do 60 | raise "Should not be evaluated" 61 | end 62 | 63 | But "and step with :pending option", :pending => true do 64 | raise "Should not be evaluated" 65 | end 66 | end 67 | 68 | Steps "they should be pending when :pending => STRING" do 69 | Given "step with :pending option", :pending => "WIP" do 70 | raise "Should not be evaluated" 71 | end 72 | 73 | When "step with :pending option", :pending => "POSTPONED" do 74 | raise "Should not be evaluated" 75 | end 76 | 77 | Then "step with :pending option", :pending => "DELAYED" do 78 | raise "Should not be evaluated" 79 | end 80 | end 81 | 82 | Steps "they should NOT be pending when :pending => false" do 83 | Given "step with :pending option", :pending => false do 84 | end 85 | 86 | When "step with :pending option", :pending => false do 87 | end 88 | 89 | Then "step with :pending option", :pending => false do 90 | end 91 | 92 | And "step with :pending option", :pending => false do 93 | end 94 | 95 | But "step with :pending option", :pending => false do 96 | end 97 | end 98 | end 99 | 100 | 101 | 102 | describe "Failed steps" do 103 | 104 | Steps "Given fails" do 105 | Given "thing" do 106 | 1/0 107 | end 108 | 109 | Then "I should see error" do 110 | end 111 | end 112 | 113 | 114 | Steps "When fails" do 115 | When "action" do 116 | expect(2*2).to eq(5) 117 | end 118 | 119 | Then "I should see error" do 120 | end 121 | end 122 | 123 | Steps "Then fails" do 124 | Then "result" do 125 | raise Exception 126 | end 127 | 128 | Then "I should see error" do 129 | end 130 | end 131 | 132 | end 133 | end 134 | -------------------------------------------------------------------------------- /spec/regression_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe 'Usual example' do 4 | subject { 2 + 2 } 5 | 6 | context 'success' do 7 | specify { expect(subject).to eq(4) } 8 | end 9 | 10 | context 'failed' do 11 | specify { expect(subject).to eq(5) } 12 | end 13 | 14 | context 'pending' do 15 | it 'should be pending' 16 | end 17 | end 18 | -------------------------------------------------------------------------------- /spec/spec_helper.rb: -------------------------------------------------------------------------------- 1 | require 'rspec/example_steps' 2 | --------------------------------------------------------------------------------