rspec-gherkin 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 8c9bab3b667c903dfa4cf5449becaa7778099a1e
4
+ data.tar.gz: fe2a11c885696386a5adcc938dde4204fb571266
5
+ SHA512:
6
+ metadata.gz: c0fda6e78aa39013889fdb409ec4810ecad15e3757952e0661cbccb7e60a04a8149fcebcc56c16d257fc299f9c2cdb6af20b48845e117b06fd26c250f8b8d0f6
7
+ data.tar.gz: 871433b8d10a664de7be4147d9b4fdf4745508c9eb7aba85834cab997988d93326050cfbffe1bbda8ab946e3c335cf8b2d7601727c6728ea5a272b99ce46db47
data/.gitignore ADDED
@@ -0,0 +1,5 @@
1
+ *.gem
2
+ .bundle
3
+ bundler_stubs
4
+ Gemfile.lock
5
+ pkg/*
data/.rspec ADDED
@@ -0,0 +1,3 @@
1
+ -r rspec-gherkin
2
+ --color
3
+ --tag ~feature
data/.travis.yml ADDED
@@ -0,0 +1,11 @@
1
+ rvm:
2
+ - 1.9.2
3
+ - 1.9.3
4
+ - ruby-head
5
+ - rbx-19mode
6
+ matrix:
7
+ allow_failures:
8
+ - rvm: ruby-head
9
+ script:
10
+ bundle exec rspec
11
+
data/Gemfile ADDED
@@ -0,0 +1,2 @@
1
+ source "http://rubygems.org"
2
+ gemspec
data/README.md ADDED
@@ -0,0 +1,125 @@
1
+ # RSpec Gherkin [![Build Status][travis-img-url]][travis-url]
2
+
3
+ [travis-img-url]: https://travis-ci.org/sheerun/rspec-gherkin.png
4
+ [travis-url]: https://travis-ci.org/rspec-gherkin
5
+
6
+ Different approach to Gherkin features in RSpec. It is based on two premises:
7
+
8
+ 1. Requirements are written by **business** in semi-formal, human-readable Gherkin.
9
+ 2. Automation of those is done by **programmers** in formal, machine-readable RSpec.
10
+
11
+ It resigns from the idea of regexp-parseable Cucumber features. As Uncle Bob [noticed in his article](http://blog.8thlight.com/uncle-bob/2013/09/26/AT-FAIL.html):
12
+
13
+ > I mean, the point was to get the *business* to provide a formal specification of the system so that the *programmers* could understand it. What in the name of heaven is the point of having the *programmers* write the formal specification so that the *programmers* can then understand it?
14
+
15
+ ## Installation
16
+
17
+ Add this gem to `test` group in `Gemfile`:
18
+
19
+ ```ruby
20
+ group :test do
21
+ gem 'rspec-gherkin'
22
+ end
23
+ ```
24
+
25
+ In your `spec_helper` include environment and `rspec-gherkin`:
26
+
27
+ ```ruby
28
+ require File.expand_path('../../config/environment', __FILE__)
29
+ require 'capybara/rails' # only for Rails
30
+ require 'rspec-gherkin'
31
+ ```
32
+
33
+ ## Basic Usage
34
+
35
+ 1. Put your requirements in `features` directory under application's root path:
36
+
37
+ ```
38
+ features/manage_articles.feature
39
+ ```
40
+
41
+ ```
42
+ Feature: Manage Articles
43
+ In order to make a blog
44
+ As an author
45
+ I want to create and manage articles
46
+
47
+ Scenario: Articles List
48
+ Given I have articles titled Pizza, Breadsticks
49
+ When I go to the list of articles
50
+ Then I should see "Pizza"
51
+ And I should see "Breadsticks"
52
+ ```
53
+
54
+ 2. Put specs for for those features in `spec/features` directory:
55
+
56
+ ```
57
+ spec/features/manage_articles_spec.rb
58
+ ```
59
+
60
+ ```ruby
61
+ require 'spec_helper'
62
+
63
+ feature 'Manage Articles' do
64
+ scenario 'Articles List' do
65
+ create(:article, :title => "Pizza")
66
+ create(:article, :title => "Breadsticks")
67
+ visit articles_path
68
+ expect(page).to have_content 'Pizza'
69
+ expect(page).to have_content 'Breadsticks'
70
+ end
71
+ end
72
+ ```
73
+
74
+ In specs you can use Capybara, FactoryGirl, helpers, and whatever you want.
75
+
76
+ You can run both `*.feature` files and `_spec.rb` spec as usual.
77
+
78
+ ```sh
79
+ # Run all features
80
+ rspec features
81
+ rspec spec/features
82
+ rspec --tag feature
83
+
84
+ # Run individual features
85
+ rspec features/manage_articles.feature
86
+ rspec spec/features/manage_articles_spec.rb
87
+ ```
88
+
89
+ You may want to add `--tag ~feature` to your `.rspec` file to not run
90
+ slow features specs by default.
91
+
92
+ ## Configuration
93
+
94
+ By default features in `features` directory are mapped to specs in `spec/features`.
95
+
96
+ Also each feature has an additional metadata: `{ :type => :feature, :feature => true }`.
97
+
98
+ You can change this by adding configuration options in `spec_helper`. Here are the defaults:
99
+
100
+ ```ruby
101
+ RSpec.configure do |config|
102
+ config.feature_mapping = {
103
+ :feature => 'features/**/*.feature',
104
+ :spec => 'spec/features/**/*_spec.rb'
105
+ }
106
+ config.feature_metadata = { :type => :feature, :feature => :true }
107
+ end
108
+ ```
109
+
110
+ ## FAQ
111
+
112
+ *How it differs from `capybara/rspec`*
113
+
114
+ It is an extension to it. `rspec-gherin` among others:
115
+
116
+ 1. Focuses on strong mapping between features and specs for them
117
+ 2. Allows for running feature files directly
118
+ 3. Notifies if any features/scenarios have pending specs
119
+ 4. Notifies if any specs have no matching features/scenarios
120
+ 5. Marks specs as pending if matchinf feature has been tagged as `@updated`
121
+ 6. Provides RSpec messages, indicating location of feature and spec files.
122
+
123
+ ## License
124
+
125
+ This gem is MIT-licensed. You are awesome.
data/Rakefile ADDED
@@ -0,0 +1 @@
1
+ require "bundler/gem_tasks"
@@ -0,0 +1 @@
1
+ Feature: Missing scenario
@@ -0,0 +1,10 @@
1
+ Feature: using scenario outlines
2
+ Scenario Outline: a simple outline
3
+ Given there is a monster with <hp> hitpoints
4
+ When I attack the monster and do <damage> points damage
5
+ Then the monster should be <state>
6
+
7
+ Examples:
8
+ | hp | damage | state | happy |
9
+ | 10.0 | 13 | dead | false |
10
+ | 8.0 | 5 | alive | true |
@@ -0,0 +1,16 @@
1
+ Feature: A simple feature
2
+ Background:
3
+ Given we live in monster world
4
+ Scenario: A simple scenario
5
+ Given there is a monster
6
+ When I attack it
7
+ Then it should die
8
+ Scenario: Raising error
9
+ When Running this scenario
10
+ Then Error should be raisen
11
+ Scenario: Diferant metadata type
12
+ When Running this scenario
13
+ Then Type of this scenario should be :controller
14
+ Scenario: Custom metadata tag
15
+ When Running this scenario
16
+ Then Metadata should contain :custom key with 'foobar' value
@@ -0,0 +1,12 @@
1
+ @updated
2
+ Feature: Updated feature
3
+ Scenario: Attack a monster with cool tag
4
+ Given there is a monster
5
+ When I attack it
6
+ Then it should die
7
+
8
+ Scenario: Attack another monster
9
+ Given there is a strong monster
10
+ When I attack it
11
+ And I attack it
12
+ Then it should die
@@ -0,0 +1,12 @@
1
+ Feature: Feature with updated scenario
2
+ @updated
3
+ Scenario: Updated scenario
4
+ Given there is a monster
5
+ When I attack it
6
+ Then it should die
7
+
8
+ Scenario: Attack another monster
9
+ Given there is a strong monster
10
+ When I attack it
11
+ And I attack it
12
+ Then it should die
@@ -0,0 +1,157 @@
1
+ require "gherkin"
2
+
3
+ module RSpecGherkin
4
+ class Builder
5
+ module Tags
6
+ def tags
7
+ @raw.tags.map { |tag| tag.name.sub(/^@/, '') }
8
+ end
9
+
10
+ def tags_hash
11
+ Hash[tags.map { |t| [t.to_sym, true] }]
12
+ end
13
+
14
+ def metadata_hash
15
+ tags_hash
16
+ end
17
+ end
18
+
19
+ module Name
20
+ def name
21
+ @raw.name
22
+ end
23
+ end
24
+
25
+ class Feature
26
+ include Tags
27
+ include Name
28
+
29
+ attr_reader :scenarios, :backgrounds
30
+ attr_accessor :feature_tag
31
+
32
+ def initialize(raw)
33
+ @raw = raw
34
+ @scenarios = []
35
+ @backgrounds = []
36
+ end
37
+
38
+ def line
39
+ @raw.line
40
+ end
41
+ end
42
+
43
+ class Background
44
+ def initialize(raw)
45
+ @raw = raw
46
+ end
47
+ end
48
+
49
+ class Scenario
50
+ include Tags
51
+ include Name
52
+
53
+ attr_accessor :arguments
54
+
55
+ def initialize(raw)
56
+ @raw = raw
57
+ @arguments = []
58
+ end
59
+ end
60
+
61
+ class Step < Struct.new(:description, :extra_args, :line)
62
+ # 1.9.2 support hack
63
+ def split(*args)
64
+ self.to_s.split(*args)
65
+ end
66
+
67
+ def to_s
68
+ description
69
+ end
70
+ end
71
+
72
+ attr_reader :features
73
+
74
+ class << self
75
+ def build(feature_file)
76
+ RSpecGherkin::Builder.new.tap do |builder|
77
+ parser = Gherkin::Parser::Parser.new(builder, true)
78
+ parser.parse(File.read(feature_file), feature_file, 0)
79
+ end
80
+ end
81
+ end
82
+
83
+ def initialize
84
+ @features = []
85
+ end
86
+
87
+ def background(background)
88
+ @current_step_context = Background.new(background)
89
+ @current_feature.backgrounds << @current_step_context
90
+ end
91
+
92
+ def feature(feature)
93
+ @current_feature = Feature.new(feature)
94
+ @features << @current_feature
95
+ end
96
+
97
+ def scenario(scenario)
98
+ @current_step_context = Scenario.new(scenario)
99
+ @current_feature.scenarios << @current_step_context
100
+ end
101
+
102
+ def scenario_outline(outline)
103
+ @current_scenario_template = outline
104
+ end
105
+
106
+ def examples(examples)
107
+ rows_to_array(examples.rows).each do |arguments|
108
+ scenario = Scenario.new(@current_scenario_template)
109
+ scenario.arguments = arguments.map do |argument|
110
+ if numeric?(argument)
111
+ integer?(argument) ? argument.to_i : argument.to_f
112
+ elsif boolean?(argument)
113
+ to_bool(argument)
114
+ else
115
+ argument
116
+ end
117
+ end
118
+
119
+ @current_feature.scenarios << scenario
120
+ end
121
+ end
122
+
123
+ def step(*)
124
+ end
125
+
126
+ def uri(*)
127
+ end
128
+
129
+ def eof
130
+ end
131
+
132
+ private
133
+
134
+ def integer?(string)
135
+ return true if string =~ /^\d+$/
136
+ end
137
+
138
+ def numeric?(string)
139
+ return true if string =~ /^\d+$/
140
+ true if Float(string) rescue false
141
+ end
142
+
143
+ def boolean?(string)
144
+ string =~ (/(true|t|yes|y)$/i) ||
145
+ string =~ (/(false|f|no|n)$/i)
146
+ end
147
+
148
+ def to_bool(string)
149
+ return true if string =~ (/(true|t|yes|y|1)$/i)
150
+ return false if string =~ (/(false|f|no|n|0)$/i)
151
+ end
152
+
153
+ def rows_to_array(rows)
154
+ rows.map { |row| row.cells(&:value) }.drop(1)
155
+ end
156
+ end
157
+ end
@@ -0,0 +1,112 @@
1
+ require "capybara/rspec" rescue nil
2
+
3
+ class << self
4
+ def feature(name = nil, new_metadata = {}, &block)
5
+ raise ArgumentError.new("requires a name") if name.nil?
6
+
7
+ new_metadata = ::RSpec.configuration.feature_metadata.merge(new_metadata)
8
+ matching_feature = find_feature(name)
9
+
10
+ if matching_feature
11
+ if matching_feature.tags.include?('updated')
12
+ pending_feature(name, new_metadata, block.source_location, [
13
+ "Feature has been marked as updated",
14
+ "Update specs for this feature and remove the @updated tag",
15
+ "Feature file: '#{feature_path(block.source_location)}'"
16
+ ])
17
+ else
18
+ describe("Feature: #{name}", new_metadata.merge(:current_feature => matching_feature), &block)
19
+ end
20
+ else
21
+ pending_feature(name, new_metadata, block.source_location,
22
+ "No such feature in '#{feature_path(block.source_location)}'"
23
+ )
24
+ end
25
+ end
26
+
27
+ private
28
+
29
+ def find_feature(name)
30
+ RSpecGherkin.features.find do |feature|
31
+ feature.name == name
32
+ end
33
+ end
34
+
35
+ def feature_path(spec_location)
36
+ RSpecGherkin.spec_to_feature(spec_location.first, false)
37
+ end
38
+
39
+ def pending_feature(name, new_metadata, spec_location, reason)
40
+ describe "Feature: #{name}", new_metadata do
41
+ it do
42
+ example.metadata.merge!(
43
+ file_path: spec_location[0],
44
+ line_number: spec_location[1]
45
+ )
46
+
47
+ pending [*reason].join("\n # ")
48
+ end
49
+ end
50
+ end
51
+ end
52
+
53
+ module RSpecGherkin
54
+ module DSL
55
+ module Rspec
56
+ def background(&block)
57
+ before(:each, &block)
58
+ end
59
+
60
+ def scenario(name = nil, new_metadata = {}, &block)
61
+ raise ArgumentError.new("requires a name") if name.nil?
62
+
63
+ matching_scenario = find_scenario(self.metadata[:current_feature], name)
64
+
65
+ if matching_scenario
66
+ if matching_scenario.tags.include?('updated')
67
+ pending_scenario(name, new_metadata, block.source_location, [
68
+ "Scenario has been marked as updated",
69
+ "Update specs for this scenario and remove the @updated tag",
70
+ "Feature file: '#{feature_path(block.source_location)}'"
71
+ ])
72
+ elsif matching_scenario.arguments
73
+ specify "Scenario: #{name}", new_metadata do
74
+ instance_exec(*matching_scenario.arguments, &block)
75
+ end
76
+ else
77
+ specify("Scenario: #{name}", new_metadata, &block)
78
+ end
79
+ else
80
+ pending_scenario(name, new_metadata, block.source_location,
81
+ "No such scenario in '#{feature_path(block.source_location)}'"
82
+ )
83
+ end
84
+ end
85
+
86
+ private
87
+
88
+ def find_scenario(feature, name)
89
+ feature.scenarios.find do |scenario|
90
+ scenario.name == name
91
+ end
92
+ end
93
+
94
+ def feature_path(spec_location)
95
+ RSpecGherkin.spec_to_feature(spec_location.first, false)
96
+ end
97
+
98
+ def pending_scenario(name, new_metadata, spec_location, reason)
99
+ specify name, new_metadata do
100
+ example.metadata.merge!(
101
+ file_path: spec_location[0],
102
+ line_number: spec_location[1]
103
+ )
104
+ example.metadata[:example_group].merge!(
105
+ description_args: ["Scenario:"]
106
+ )
107
+ pending [*reason].join("\n # ")
108
+ end
109
+ end
110
+ end
111
+ end
112
+ end
@@ -0,0 +1,56 @@
1
+ require "rspec-gherkin"
2
+ require "rspec"
3
+
4
+ module RSpecGherkin
5
+ module RSpec
6
+ module Loader
7
+ def load(*paths, &block)
8
+
9
+ # Override feature exclusion filter if running features
10
+ if paths.any? { |path| RSpecGherkin.feature?(path) }
11
+ ::RSpec.configuration.filter_manager.exclusions.reject! do |key, value|
12
+ key == :feature || (key == :type && value == 'feature')
13
+ end
14
+ end
15
+
16
+ paths = paths.map do |path|
17
+ if RSpecGherkin.feature?(path)
18
+ spec_path = RSpecGherkin.feature_to_spec(path)
19
+ if File.exist?(spec_path)
20
+ spec_path
21
+ else
22
+ RSpecGherkin::Builder.build(path).features.each do |feature|
23
+ ::RSpec::Core::ExampleGroup.describe(
24
+ "Feature: #{feature.name}", :type => :feature, :feature => true
25
+ ) do
26
+ it do
27
+ example.metadata[:file_path] = spec_path
28
+ example.metadata[:line_number] = 1
29
+ pending('Not yet implemented')
30
+ end
31
+ end.register
32
+ end
33
+
34
+ nil
35
+ end
36
+ else
37
+ path
38
+ end
39
+ end.compact
40
+
41
+ # Load needed features to RSpecGherkin.features array
42
+ paths.each do |path|
43
+ if RSpecGherkin.feature_spec?(path)
44
+ feature_path = RSpecGherkin.spec_to_feature(path)
45
+
46
+ if File.exists?(feature_path)
47
+ RSpecGherkin.features += RSpecGherkin::Builder.build(feature_path).features
48
+ end
49
+ end
50
+ end
51
+
52
+ super(*paths, &block) if paths.size > 0
53
+ end
54
+ end
55
+ end
56
+ end
@@ -0,0 +1,3 @@
1
+ module RSpecGherkin
2
+ VERSION = "0.1.0"
3
+ end
@@ -0,0 +1,68 @@
1
+ require "rspec-gherkin/builder"
2
+ require "rspec-gherkin/rspec-dsl"
3
+ require "rspec-gherkin/rspec-loader"
4
+ require "rspec-gherkin/version"
5
+
6
+ module RSpecGherkin extend self
7
+
8
+ class << self
9
+ attr_accessor :features
10
+ end
11
+
12
+ class Pending < StandardError; end
13
+ class Malformed < StandardError; end
14
+ class Ambiguous < StandardError; end
15
+
16
+ def feature?(path)
17
+ !!path.match(mask_to_pattern(feature_mask))
18
+ end
19
+
20
+ def feature_spec?(path)
21
+ !!path.match(mask_to_pattern(spec_mask))
22
+ end
23
+
24
+ def feature_to_spec(path, prefix = true)
25
+ path = path.match(mask_to_pattern(feature_mask))[0] unless prefix
26
+ path.sub(mask_to_pattern(feature_mask), mask_to_replacement(spec_mask))
27
+ end
28
+
29
+ def spec_to_feature(path, prefix = true)
30
+ path = path.match(mask_to_pattern(spec_mask))[0] unless prefix
31
+ path.sub(mask_to_pattern(spec_mask), mask_to_replacement(feature_mask))
32
+ end
33
+
34
+ protected
35
+
36
+ def spec_mask
37
+ ::RSpec.configuration.feature_mapping[:spec]
38
+ end
39
+
40
+ def feature_mask
41
+ ::RSpec.configuration.feature_mapping[:feature]
42
+ end
43
+
44
+ def mask_to_pattern(mask)
45
+ Regexp.new("#{Regexp.escape(mask).sub("\\*\\*/\\*", '(.+)')}$")
46
+ end
47
+
48
+ def mask_to_replacement(mask)
49
+ "#{mask.sub('**/*'){ '\\1' }}"
50
+ end
51
+
52
+ end
53
+
54
+ RSpecGherkin.features = []
55
+
56
+ ::RSpec.configure do |config|
57
+ config.extend RSpecGherkin::DSL::Rspec
58
+ config.pattern << ",**/*.feature"
59
+ config.add_setting :feature_mapping
60
+ config.add_setting :feature_metadata
61
+ config.feature_mapping = {
62
+ :feature => 'features/**/*.feature',
63
+ :spec => 'spec/features/**/*_spec.rb'
64
+ }
65
+ config.feature_metadata = { :type => :feature, :feature => :true }
66
+ end
67
+
68
+ ::RSpec::Core::Configuration.send(:include, RSpecGherkin::RSpec::Loader)
@@ -0,0 +1,22 @@
1
+ # encoding: utf-8
2
+ $:.push File.expand_path("../lib", __FILE__)
3
+ require "rspec-gherkin/version"
4
+
5
+ Gem::Specification.new do |s|
6
+ s.name = "rspec-gherkin"
7
+ s.version = RSpecGherkin::VERSION
8
+ s.authors = ["Adam Stankiewicz"]
9
+ s.email = ["sheerun@sher.pl"]
10
+ s.homepage = ""
11
+ s.summary = %q{Different approach to Gherkin features in RSpec}
12
+ s.description = %q{Different approach to Gherkin features in RSpec}
13
+
14
+ s.files = `git ls-files`.split("\n")
15
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
16
+ s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
17
+ s.require_paths = ["lib"]
18
+
19
+ s.add_runtime_dependency "rspec", "~> 2.0"
20
+ s.add_runtime_dependency "gherkin", ">= 2.5"
21
+ s.add_development_dependency "rake"
22
+ end
@@ -0,0 +1,21 @@
1
+ require 'spec_helper'
2
+
3
+ describe RSpecGherkin::Builder do
4
+ context "with scenario outlines" do
5
+ let(:feature_file) { File.expand_path('../features/scenario_outline.feature', File.dirname(__FILE__)) }
6
+ let(:builder) { RSpecGherkin::Builder.build(feature_file) }
7
+ let(:feature) { builder.features.first }
8
+
9
+ it "extracts scenario" do
10
+ feature.scenarios.map(&:name).should eq([
11
+ 'a simple outline',
12
+ 'a simple outline'
13
+ ])
14
+ end
15
+
16
+ it "add additional arguments to scenarios" do
17
+ feature.scenarios[0].arguments.should eq([ 10.0, 13, "dead", false ])
18
+ feature.scenarios[1].arguments.should eq([ 8.0, 5, "alive", true ])
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,7 @@
1
+ require 'spec_helper'
2
+
3
+ feature 'Missing feature' do
4
+ scenario 'This should never be executed' do
5
+ raise 'Scenario in spec with missing feature should not be executed'
6
+ end
7
+ end
@@ -0,0 +1,5 @@
1
+ feature 'Missing scenario' do
2
+ scenario 'Non-existing scenario' do
3
+ expect(1).to eq(1)
4
+ end
5
+ end
@@ -0,0 +1,10 @@
1
+ require 'spec_helper'
2
+
3
+ feature 'using scenario outlines' do
4
+ scenario 'a simple outline' do |hp, damage, state, happy|
5
+ expect(hp).to be_a(Float)
6
+ expect(damage).to be_a(Fixnum)
7
+ expect(state).to be_a(String)
8
+ expect([true, false]).to include happy
9
+ end
10
+ end
@@ -0,0 +1,26 @@
1
+ require 'spec_helper'
2
+
3
+ feature 'A simple feature' do
4
+ # ensure background is executed as before(:each)
5
+ background do
6
+ @number ||= 41
7
+ @number += 1
8
+ end
9
+
10
+ scenario 'A simple scenario' do
11
+ expect(@number).to eq(42)
12
+ end
13
+
14
+ scenario 'Raising error' do
15
+ raise ArgumentError.new("Your argument is invalid!")
16
+ end
17
+
18
+ scenario 'Diferant metadata type', :type => :controller, :feature => false do
19
+ expect(example.metadata[:type]).to eq(:controller)
20
+ expect(example.metadata[:feature]).to eq(false)
21
+ end
22
+
23
+ scenario 'Custom metadata tag', :custom => "foobar" do
24
+ expect(example.metadata[:custom]).to eq("foobar")
25
+ end
26
+ end
@@ -0,0 +1,11 @@
1
+ # This feature should be marked as pending
2
+ # because it is tagged as @updated in gherkin
3
+ feature 'Updated feature' do
4
+ scenario 'Attack a monster with cool tag' do
5
+ expect(1).to eq(1)
6
+ end
7
+
8
+ scenario 'Attack another monster' do
9
+ expect(1).to eq(1)
10
+ end
11
+ end
@@ -0,0 +1,11 @@
1
+ # This feature should be marked as pending
2
+ # because it is tagged as @updated in gherkin
3
+ feature 'Feature with updated scenario' do
4
+ scenario 'Updated scenario' do
5
+ expect(1).to eq(1)
6
+ end
7
+
8
+ scenario 'Attack another monster' do
9
+ expect(1).to eq(1)
10
+ end
11
+ end
@@ -0,0 +1,104 @@
1
+ require 'spec_helper'
2
+
3
+ describe 'The CLI', :type => :integration do
4
+ context 'runing features from features directory' do
5
+ it 'ignores --tag ~feature flag when running features' do
6
+ expect(%x(rspec features --tag ~feature 2>&1)).
7
+ to include('9 examples, 1 failure, 3 pending')
8
+ end
9
+
10
+ it 'ignores --tag ~type:feature flag when running features' do
11
+ expect(%x(rspec features --tag ~type:feature 2>&1)).
12
+ to include('9 examples, 1 failure, 3 pending')
13
+ end
14
+ end
15
+
16
+ context 'runing features specs on their own' do
17
+ before(:all) do
18
+ @result = %x(rspec --tag feature --format documentation 2>&1)
19
+ end
20
+
21
+ it 'passes all specs' do
22
+ expect(@result).to include('9 examples, 1 failure, 4 pending')
23
+ end
24
+
25
+ it 'prepends features with "Feature: " prefix' do
26
+ expect(@result).to include('Feature: A simple feature')
27
+ end
28
+
29
+ it 'prepends scenarios with "Scenario: " prefix' do
30
+ expect(@result).to include('Scenario: A simple scenario')
31
+ end
32
+
33
+ context 'non-existing scenario' do
34
+ it 'shows name of non-existing scenario' do
35
+ expect(@result).to include(
36
+ "Scenario: Non-existing scenario"
37
+ )
38
+ end
39
+
40
+ it 'shows that spec implements non-existing scenario' do
41
+ expect(@result).to include(
42
+ "No such scenario in 'features/no_scenario.feature'"
43
+ )
44
+ end
45
+
46
+ it 'shows line number where missing scenario is mentioned' do
47
+ expect(@result).to include(
48
+ "./spec/features/no_scenario_spec.rb:2"
49
+ )
50
+ end
51
+ end
52
+
53
+ context 'non-existing feature' do
54
+ it 'shows name of non-existing feature' do
55
+ expect(@result).to include(
56
+ "Feature: Missing feature"
57
+ )
58
+ end
59
+
60
+ it 'shows that spec implements non-existing feature' do
61
+ expect(@result).to include(
62
+ "No such feature in 'features/no_feature.feature'"
63
+ )
64
+ end
65
+
66
+ it 'shows line number where missing scenario is mentioned' do
67
+ expect(@result).to include(
68
+ "./spec/features/no_feature_spec.rb:3"
69
+ )
70
+ end
71
+ end
72
+
73
+ context 'updated features and scenarios' do
74
+ it 'recognizes and notifies when feature is marked as @updated' do
75
+ expect(@result).to include(
76
+ 'Feature has been marked as updated'
77
+ )
78
+ end
79
+
80
+ it 'recognizes and notifies when scenario is marked as @updated' do
81
+ expect(@result).to include(
82
+ 'Scenario has been marked as updated'
83
+ )
84
+ end
85
+ end
86
+ end
87
+
88
+ # it "shows the correct description" do
89
+ # @result.should include('A simple feature')
90
+ # @result.should include('is a simple feature')
91
+ # end
92
+
93
+ # it "prints out failures and successes" do
94
+ # @result.should include('35 examples, 3 failures, 5 pending')
95
+ # end
96
+
97
+ # it "includes features in backtraces" do
98
+ # @result.should include('examples/errors.feature:5:in `raise error')
99
+ # end
100
+
101
+ # it "includes the right step name when steps call steps" do
102
+ # @result.should include("No such step: 'this is an unimplemented step'")
103
+ # end
104
+ end
@@ -0,0 +1,56 @@
1
+ describe RSpecGherkin do
2
+ let(:feature_path) { '/project/features/awesome-def_file.feature' }
3
+ let(:spec_path) { '/project/spec/features/awesome-def_file_spec.rb' }
4
+
5
+ let(:short_feature_path) { 'features/awesome-def_file.feature' }
6
+ let(:short_spec_path) { 'spec/features/awesome-def_file_spec.rb' }
7
+
8
+ context '#feature?' do
9
+ it 'recognizes if path is feature path' do
10
+ expect(RSpecGherkin.feature?(feature_path)).to eq(true)
11
+ end
12
+
13
+ it 'recognizes if path is not feature path' do
14
+ expect(RSpecGherkin.feature?(spec_path)).to eq(false)
15
+ end
16
+ end
17
+
18
+ context '#feature_spec?' do
19
+ it 'recognizes if path is spec path' do
20
+ expect(RSpecGherkin.feature_spec?(spec_path)).to eq(true)
21
+ end
22
+
23
+ it 'recognizes if path is not spec path' do
24
+ expect(RSpecGherkin.feature_spec?(feature_path)).to eq(false)
25
+ end
26
+ end
27
+
28
+ context '#feature_to_spec' do
29
+ it 'properly translates feature file to spec file' do
30
+ expect(RSpecGherkin.feature_to_spec(feature_path)).to eq(spec_path)
31
+ end
32
+
33
+ it 'excludes prefix when requested' do
34
+ expect(RSpecGherkin.feature_to_spec(feature_path, false)).
35
+ to eq(short_spec_path)
36
+ end
37
+ end
38
+
39
+ context '#spec_to_feature' do
40
+ it 'properly translates spec file to feature file' do
41
+ expect(RSpecGherkin.spec_to_feature(spec_path)).
42
+ to eq(feature_path)
43
+ end
44
+
45
+ it 'excludes prefix when requested' do
46
+ expect(RSpecGherkin.spec_to_feature(spec_path, false)).
47
+ to eq(short_feature_path)
48
+ end
49
+ end
50
+
51
+ specify '#spec_to_feature and #feature_to_spec should be idempotent' do
52
+ p1 = RSpecGherkin.feature_to_spec(RSpecGherkin.spec_to_feature(spec_path))
53
+ p2 = RSpecGherkin.feature_to_spec(feature_path)
54
+ expect(p1).to eq(p2)
55
+ end
56
+ end
File without changes
metadata ADDED
@@ -0,0 +1,128 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: rspec-gherkin
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Adam Stankiewicz
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2013-10-08 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: rspec
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ~>
18
+ - !ruby/object:Gem::Version
19
+ version: '2.0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ~>
25
+ - !ruby/object:Gem::Version
26
+ version: '2.0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: gherkin
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - '>='
32
+ - !ruby/object:Gem::Version
33
+ version: '2.5'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - '>='
39
+ - !ruby/object:Gem::Version
40
+ version: '2.5'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rake
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - '>='
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - '>='
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ description: Different approach to Gherkin features in RSpec
56
+ email:
57
+ - sheerun@sher.pl
58
+ executables: []
59
+ extensions: []
60
+ extra_rdoc_files: []
61
+ files:
62
+ - .gitignore
63
+ - .rspec
64
+ - .travis.yml
65
+ - Gemfile
66
+ - README.md
67
+ - Rakefile
68
+ - features/no_scenario.feature
69
+ - features/scenario_outline.feature
70
+ - features/simple_feature.feature
71
+ - features/updated_feature.feature
72
+ - features/updated_scenario.feature
73
+ - lib/rspec-gherkin.rb
74
+ - lib/rspec-gherkin/builder.rb
75
+ - lib/rspec-gherkin/rspec-dsl.rb
76
+ - lib/rspec-gherkin/rspec-loader.rb
77
+ - lib/rspec-gherkin/version.rb
78
+ - rspec-gherkin.gemspec
79
+ - spec/builder_spec.rb
80
+ - spec/features/no_feature_spec.rb
81
+ - spec/features/no_scenario_spec.rb
82
+ - spec/features/scenario_outline_spec.rb
83
+ - spec/features/simple_feature_spec.rb
84
+ - spec/features/updated_feature_spec.rb
85
+ - spec/features/updated_scenario_spec.rb
86
+ - spec/integration_spec.rb
87
+ - spec/rspec-gherkin_spec.rb
88
+ - spec/spec_helper.rb
89
+ homepage: ''
90
+ licenses: []
91
+ metadata: {}
92
+ post_install_message:
93
+ rdoc_options: []
94
+ require_paths:
95
+ - lib
96
+ required_ruby_version: !ruby/object:Gem::Requirement
97
+ requirements:
98
+ - - '>='
99
+ - !ruby/object:Gem::Version
100
+ version: '0'
101
+ required_rubygems_version: !ruby/object:Gem::Requirement
102
+ requirements:
103
+ - - '>='
104
+ - !ruby/object:Gem::Version
105
+ version: '0'
106
+ requirements: []
107
+ rubyforge_project:
108
+ rubygems_version: 2.0.3
109
+ signing_key:
110
+ specification_version: 4
111
+ summary: Different approach to Gherkin features in RSpec
112
+ test_files:
113
+ - features/no_scenario.feature
114
+ - features/scenario_outline.feature
115
+ - features/simple_feature.feature
116
+ - features/updated_feature.feature
117
+ - features/updated_scenario.feature
118
+ - spec/builder_spec.rb
119
+ - spec/features/no_feature_spec.rb
120
+ - spec/features/no_scenario_spec.rb
121
+ - spec/features/scenario_outline_spec.rb
122
+ - spec/features/simple_feature_spec.rb
123
+ - spec/features/updated_feature_spec.rb
124
+ - spec/features/updated_scenario_spec.rb
125
+ - spec/integration_spec.rb
126
+ - spec/rspec-gherkin_spec.rb
127
+ - spec/spec_helper.rb
128
+ has_rdoc: