yari 0.0.2

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.
@@ -0,0 +1,3 @@
1
+ module Yari
2
+ VERSION = "0.0.2"
3
+ end
@@ -0,0 +1,125 @@
1
+ class << self
2
+ def feature(name = nil, new_metadata = {}, &block)
3
+ raise ArgumentError.new("requires a name") if name.nil?
4
+
5
+ new_metadata = ::RSpec.configuration.feature_metadata.merge(new_metadata)
6
+ matching_feature = find_feature(name)
7
+ new_metadata[:feature_name]= name
8
+
9
+ if matching_feature
10
+ if matching_feature.tags.include?('@updated')
11
+ pending_feature(name, new_metadata, block.source_location,
12
+ "Feature has been marked as updated\n \t# Update specs for this feature and remove the @updated tag\n \t# Feature file: '#{feature_path(block.source_location)}"
13
+ )
14
+ else
15
+ describe("Feature: #{name}", new_metadata.merge(:current_feature => matching_feature), &block)
16
+ end
17
+ else
18
+ pending_feature(name, new_metadata, block.source_location, "No such feature in '#{feature_path(block.source_location)}'")
19
+ end
20
+ end
21
+
22
+ private
23
+
24
+ def find_feature(name)
25
+ Yari.features.find do |feature|
26
+ feature.name == name
27
+ end
28
+ end
29
+
30
+ def feature_path(spec_location)
31
+ Yari.spec_to_feature(spec_location.first, false)
32
+ end
33
+
34
+ def pending_feature(name, new_metadata, spec_location, reason)
35
+ describe "Feature: #{name}", new_metadata do
36
+ it do |example|
37
+ example.metadata.merge!(
38
+ file_path: spec_location[0],
39
+ location: "#{spec_location[0]}:#{spec_location[1]}"
40
+ )
41
+ skip reason
42
+ end
43
+ end
44
+ end
45
+ end
46
+
47
+ module Yari
48
+ module DSL
49
+ module Rspec
50
+ def background(&block)
51
+ before(:each, &block)
52
+ end
53
+
54
+ def scenario(name = nil, new_metadata = {}, &block)
55
+ raise ArgumentError.new("requires a name") if name.nil?
56
+
57
+ matching_scenario = find_scenario(self.metadata[:current_feature], name)
58
+ new_metadata[:scenario_name]= name
59
+
60
+ if matching_scenario
61
+ if matching_scenario.tags.include?('@updated')
62
+ pending_scenario(name, new_metadata, block.source_location,
63
+ "Scenario has been marked as updated\n \t# Update specs for this scenario and remove the @updated tag\n \t# Feature file: '#{feature_path(block.source_location)}'"
64
+ )
65
+ # elsif matching_scenario.arguments
66
+ # specify "Scenario: #{name}", new_metadata do
67
+ # instance_exec(*matching_scenario.arguments, &block)
68
+ # end
69
+ else
70
+ specify("Scenario: #{name}", new_metadata, &block)
71
+ end
72
+ else
73
+ pending_scenario(name, new_metadata, block.source_location, "No such scenario in '#{feature_path(block.source_location)}'")
74
+ end
75
+ end
76
+
77
+
78
+ def scenario_with_test_cases(name = nil, new_metadata = {}, &block)
79
+ raise ArgumentError.new("requires a name") if name.nil?
80
+
81
+ matching_scenario = find_scenario(self.metadata[:current_feature], name)
82
+
83
+ if matching_scenario
84
+ if matching_scenario.tags.include?('@updated')
85
+ pending_scenario(name, new_metadata, block.source_location,
86
+ "Scenario has been marked as updated\n \t# Update specs for this scenario and remove the @updated tag\n \t# Feature file: '#{feature_path(block.source_location)}'"
87
+ )
88
+ else
89
+ describe("Scenario: #{name}", new_metadata.merge(:scenario_name => name), &block)
90
+ end
91
+ else
92
+ pending_scenario(name, new_metadata, block.source_location, "No such scenario in '#{feature_path(block.source_location)}'")
93
+ end
94
+ end
95
+
96
+ def test_case(name = nil, new_metadata = {}, &block)
97
+ raise ArgumentError.new("requires a name") if name.nil?
98
+ new_metadata[:test_case_name]= name
99
+ specify("Test_Case: #{name}", new_metadata, &block)
100
+ end
101
+
102
+ private
103
+
104
+ def find_scenario(feature, name)
105
+ feature.scenarios.find do |scenario|
106
+ scenario.name == name
107
+ end
108
+ end
109
+
110
+ def feature_path(spec_location)
111
+ Yari.spec_to_feature(spec_location.first, false)
112
+ end
113
+
114
+ def pending_scenario(name, new_metadata, spec_location, reason)
115
+ specify name, new_metadata do |example|
116
+ example.metadata.merge!(
117
+ full_description: "Scenario: #{name}",
118
+ location: "#{spec_location[0]}:#{spec_location[1]}"
119
+ )
120
+ skip reason
121
+ end
122
+ end
123
+ end
124
+ end
125
+ end
@@ -0,0 +1,52 @@
1
+ require 'yari'
2
+ require 'rspec'
3
+
4
+ module Yari
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| Yari.feature?(path) }
11
+ ::RSpec.configuration.filter_manager.exclusions.rules.reject! do |key, value|
12
+ key == :feature || (key == :type && value == 'feature')
13
+ end
14
+ end
15
+
16
+ paths = paths.map do |path|
17
+ if Yari.feature?(path)
18
+ spec_path = Yari.feature_to_spec(path)
19
+ if File.exist?(spec_path)
20
+ spec_path
21
+ else
22
+ Yari::Builder.build(path).features.each do |feature|
23
+ ::RSpec.describe("Feature: #{feature.name}", :type => :feature, :feature => true) do
24
+ it do |example|
25
+ example.metadata[:location] = path << ':1'
26
+ skip('No spec implemented for feature')
27
+ end
28
+ end
29
+ end
30
+ nil
31
+ end
32
+ else
33
+ path
34
+ end
35
+ end.compact
36
+
37
+ # Load needed features to Yari.features array
38
+ paths.each do |path|
39
+ if Yari.feature_spec?(path)
40
+ feature_path = Yari.spec_to_feature(path)
41
+
42
+ if File.exists?(feature_path)
43
+ Yari.features += Yari::Builder.build(feature_path).features
44
+ end
45
+ end
46
+ end
47
+
48
+ super(*paths, &block) if paths.size > 0
49
+ end
50
+ end
51
+ end
52
+ end
@@ -0,0 +1,45 @@
1
+ require 'spec_helper'
2
+
3
+ describe Yari::Builder do
4
+
5
+ context 'a simple feature' do
6
+ let(:feature_file) { File.expand_path('../features/simple_feature.feature', File.dirname(__FILE__)) }
7
+ let(:builder) { Yari::Builder.build(feature_file) }
8
+ let(:feature) { builder.features.first }
9
+
10
+ it 'parses the feature' do
11
+ expect(feature).to be_a_kind_of(Yari::Feature)
12
+ expect(feature.name).to eq('A simple feature')
13
+ end
14
+
15
+ it 'gets all the scenarios in the feature' do
16
+ expect(feature.scenarios.count).to eq(4)
17
+ expect(feature.scenarios.first).to be_a_kind_of(Yari::Scenario)
18
+ expect(feature.scenarios.first.name).to eq('A simple scenario')
19
+ end
20
+
21
+ it 'gets tags associated with the feature' do
22
+ expect(feature.tags).to eq(['@feature_tag'])
23
+ end
24
+
25
+ it 'gets tags associated with the scenario' do
26
+ expect(feature.scenarios.first.tags).to eq(['@scenario_tag'])
27
+ end
28
+ end
29
+
30
+ context 'with scenario outlines' do
31
+ let(:feature_file) { File.expand_path('../features/scenario_outline.feature', File.dirname(__FILE__)) }
32
+ let(:builder) { Yari::Builder.build(feature_file) }
33
+ let(:feature) { builder.features.first }
34
+
35
+
36
+ it 'extracts scenario' do
37
+ expect(feature.scenarios.map(&:name)).to eq(['a simple outline'])
38
+ expect(feature.scenarios.first.type).to eq(:ScenarioOutline)
39
+ end
40
+
41
+ it 'extracts examples from an outline' do
42
+ expect(feature.scenarios.first.examples).to eq(Yari::Example)
43
+ end
44
+ end
45
+ 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 'Different metadata type', :type => :controller, :feature => false do
19
+ expect(RSpec.current_example.metadata[:type]).to eq(:controller)
20
+ expect(RSpec.current_example.metadata[:feature]).to eq(false)
21
+ end
22
+
23
+ scenario 'Custom metadata tag', :custom => "foobar" do
24
+ expect(RSpec.current_example.metadata[:custom]).to eq("foobar")
25
+ end
26
+ end
@@ -0,0 +1,13 @@
1
+ feature 'A feature with test cases' do
2
+
3
+ scenario_with_test_cases 'A scenario requiring multiple cases to prove' do
4
+ test_case 'a passing test case' do
5
+ fail('the first test case failed')
6
+ end
7
+
8
+ test_case 'a failing test case' do
9
+ fail('the second test case also also failed')
10
+ end
11
+ end
12
+
13
+ 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,87 @@
1
+ require 'spec_helper'
2
+
3
+ describe 'The CLI', :type => :integration do
4
+ context 'running features from features directory' do
5
+
6
+ it 'ignores --tag ~feature flag when running features' do
7
+ expect(%x(rspec features --tag ~feature 2>&1)).to include('11 examples, 3 failures, 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)).to include('11 examples, 3 failures, 3 pending')
12
+ end
13
+ end
14
+
15
+ context 'running features specs on their own' do
16
+ before(:all) do
17
+ @result = %x(rspec --tag feature --format documentation 2>&1)
18
+ end
19
+
20
+ it 'passes all specs' do
21
+ expect(@result).to include('11 examples, 3 failures, 4 pending')
22
+ end
23
+
24
+ it 'prepends features with "Feature: " prefix' do
25
+ expect(@result).to include('Feature: A simple feature')
26
+ end
27
+
28
+ it 'prepends scenarios with "Scenario: " prefix' do
29
+ expect(@result).to include('Scenario: A simple scenario')
30
+ end
31
+
32
+ context 'non-existing scenario' do
33
+ it 'shows name of non-existing scenario' do
34
+ expect(@result).to include("Scenario: Non-existing scenario")
35
+ end
36
+
37
+ it 'shows that spec implements non-existing scenario' do
38
+ expect(@result).to include("No such scenario in 'features/no_scenario.feature'")
39
+ end
40
+
41
+ it 'shows line number where missing scenario is mentioned' do
42
+ expect(@result).to include("/spec/features/no_scenario_spec.rb:2")
43
+ end
44
+ end
45
+
46
+ context 'non-existing feature' do
47
+ it 'shows name of non-existing feature' do
48
+ expect(@result).to include("Feature: Missing feature")
49
+ end
50
+
51
+ it 'shows that spec implements non-existing feature' do
52
+ expect(@result).to include("No such feature in 'features/no_feature.feature'")
53
+ end
54
+
55
+ it 'shows line number where missing scenario is mentioned' do
56
+ expect(@result).to include("/spec/features/no_feature_spec.rb:3")
57
+ end
58
+ end
59
+
60
+ context 'updated features and scenarios' do
61
+ it 'recognizes and notifies when feature is marked as @updated' do
62
+ expect(@result).to include('Feature has been marked as updated')
63
+ end
64
+
65
+ it 'recognizes and notifies when scenario is marked as @updated' do
66
+ expect(@result).to include('Scenario has been marked as updated')
67
+ end
68
+ end
69
+ end
70
+
71
+ # it "shows the correct description" do
72
+ # @result.should include('A simple feature')
73
+ # @result.should include('is a simple feature')
74
+ # end
75
+
76
+ # it "prints out failures and successes" do
77
+ # @result.should include('35 examples, 3 failures, 5 pending')
78
+ # end
79
+
80
+ # it "includes features in backtraces" do
81
+ # @result.should include('examples/errors.feature:5:in `raise error')
82
+ # end
83
+
84
+ # it "includes the right step name when steps call steps" do
85
+ # @result.should include("No such step: 'this is an unimplemented step'")
86
+ # end
87
+ end
@@ -0,0 +1,3 @@
1
+ require 'coveralls'
2
+ Coveralls.wear!
3
+ require 'yari'
data/spec/yari_spec.rb ADDED
@@ -0,0 +1,58 @@
1
+ require 'spec_helper'
2
+
3
+ describe Yari do
4
+ let(:feature_path) { '/project/features/awesome-def_file.feature' }
5
+ let(:spec_path) { '/project/spec/features/awesome-def_file_spec.rb' }
6
+
7
+ let(:short_feature_path) { 'features/awesome-def_file.feature' }
8
+ let(:short_spec_path) { 'spec/features/awesome-def_file_spec.rb' }
9
+
10
+ context '#feature?' do
11
+ it 'recognizes if path is feature path' do
12
+ expect(Yari.feature?(feature_path)).to eq(true)
13
+ end
14
+
15
+ it 'recognizes if path is not feature path' do
16
+ expect(Yari.feature?(spec_path)).to eq(false)
17
+ end
18
+ end
19
+
20
+ context '#feature_spec?' do
21
+ it 'recognizes if path is spec path' do
22
+ expect(Yari.feature_spec?(spec_path)).to eq(true)
23
+ end
24
+
25
+ it 'recognizes if path is not spec path' do
26
+ expect(Yari.feature_spec?(feature_path)).to eq(false)
27
+ end
28
+ end
29
+
30
+ context '#feature_to_spec' do
31
+ it 'properly translates feature file to spec file' do
32
+ expect(Yari.feature_to_spec(feature_path)).to eq(spec_path)
33
+ end
34
+
35
+ it 'excludes prefix when requested' do
36
+ expect(Yari.feature_to_spec(feature_path, false)).
37
+ to eq(short_spec_path)
38
+ end
39
+ end
40
+
41
+ context '#spec_to_feature' do
42
+ it 'properly translates spec file to feature file' do
43
+ expect(Yari.spec_to_feature(spec_path)).
44
+ to eq(feature_path)
45
+ end
46
+
47
+ it 'excludes prefix when requested' do
48
+ expect(Yari.spec_to_feature(spec_path, false)).
49
+ to eq(short_feature_path)
50
+ end
51
+ end
52
+
53
+ specify '#spec_to_feature and #feature_to_spec should be independent' do
54
+ p1 = Yari.feature_to_spec(Yari.spec_to_feature(spec_path))
55
+ p2 = Yari.feature_to_spec(feature_path)
56
+ expect(p1).to eq(p2)
57
+ end
58
+ end