spinach 0.1.5.4 → 0.2.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (69) hide show
  1. data/Gemfile +2 -0
  2. data/README.markdown +18 -12
  3. data/features/background.feature +13 -0
  4. data/features/reporting/show_step_source_location.feature +11 -1
  5. data/features/steps/automatic_feature_generation.rb +7 -7
  6. data/features/steps/background.rb +30 -0
  7. data/features/steps/exit_status.rb +12 -13
  8. data/features/steps/feature_name_guessing.rb +7 -7
  9. data/features/steps/reporting/display_run_summary.rb +22 -22
  10. data/features/steps/reporting/error_reporting.rb +7 -7
  11. data/features/steps/reporting/show_step_source_location.rb +63 -14
  12. data/features/steps/reporting/undefined_feature_reporting.rb +7 -7
  13. data/features/steps/rspec_compatibility.rb +14 -14
  14. data/features/support/error_reporting.rb +5 -5
  15. data/features/support/filesystem.rb +71 -0
  16. data/features/support/spinach_runner.rb +5 -6
  17. data/lib/spinach.rb +11 -6
  18. data/lib/spinach/background.rb +11 -0
  19. data/lib/spinach/capybara.rb +7 -1
  20. data/lib/spinach/cli.rb +36 -13
  21. data/lib/spinach/config.rb +40 -6
  22. data/lib/spinach/dsl.rb +14 -11
  23. data/lib/spinach/exceptions.rb +1 -1
  24. data/lib/spinach/feature.rb +16 -0
  25. data/lib/spinach/frameworks.rb +2 -0
  26. data/lib/spinach/{suites → frameworks}/minitest.rb +0 -0
  27. data/lib/spinach/{suites → frameworks}/rspec.rb +0 -0
  28. data/lib/spinach/generators/feature_generator.rb +12 -23
  29. data/lib/spinach/generators/step_generator.rb +5 -5
  30. data/lib/spinach/hookable.rb +6 -4
  31. data/lib/spinach/hooks.rb +12 -4
  32. data/lib/spinach/parser.rb +6 -8
  33. data/lib/spinach/parser/visitor.rb +109 -0
  34. data/lib/spinach/reporter.rb +10 -6
  35. data/lib/spinach/reporter/stdout.rb +41 -16
  36. data/lib/spinach/reporter/stdout/error_reporting.rb +2 -2
  37. data/lib/spinach/runner.rb +9 -6
  38. data/lib/spinach/runner/feature_runner.rb +40 -34
  39. data/lib/spinach/runner/scenario_runner.rb +63 -36
  40. data/lib/spinach/scenario.rb +12 -0
  41. data/lib/spinach/step.rb +10 -0
  42. data/lib/spinach/version.rb +1 -1
  43. data/spinach.gemspec +3 -3
  44. data/test/spinach/background_test.rb +6 -0
  45. data/test/spinach/capybara_test.rb +30 -13
  46. data/test/spinach/cli_test.rb +46 -1
  47. data/test/spinach/config_test.rb +39 -0
  48. data/test/spinach/dsl_test.rb +12 -10
  49. data/test/spinach/feature_steps_test.rb +3 -3
  50. data/test/spinach/feature_test.rb +6 -0
  51. data/test/spinach/{suites → frameworks}/minitest_test.rb +2 -2
  52. data/test/spinach/generators/feature_generator_test.rb +18 -58
  53. data/test/spinach/generators/step_generator_test.rb +3 -3
  54. data/test/spinach/generators_test.rb +12 -10
  55. data/test/spinach/hookable_test.rb +8 -0
  56. data/test/spinach/hooks_test.rb +6 -7
  57. data/test/spinach/parser/visitor_test.rb +173 -0
  58. data/test/spinach/parser_test.rb +14 -27
  59. data/test/spinach/reporter/stdout/error_reporting_test.rb +9 -9
  60. data/test/spinach/reporter/stdout_test.rb +15 -19
  61. data/test/spinach/reporter_test.rb +15 -0
  62. data/test/spinach/runner/feature_runner_test.rb +79 -69
  63. data/test/spinach/runner/scenario_runner_test.rb +118 -92
  64. data/test/spinach/runner_test.rb +10 -6
  65. data/test/spinach/scenario_test.rb +6 -0
  66. data/test/spinach/step_test.rb +6 -0
  67. data/test/spinach_test.rb +7 -7
  68. metadata +60 -39
  69. data/lib/spinach/suites.rb +0 -2
@@ -5,6 +5,17 @@ describe Spinach::Config do
5
5
  Spinach::Config.new
6
6
  end
7
7
 
8
+ describe '#features_path' do
9
+ it 'returns a default' do
10
+ subject[:features_path].must_be_kind_of String
11
+ end
12
+
13
+ it 'can be overwritten' do
14
+ subject[:features_path] = 'test'
15
+ subject[:features_path].must_equal 'test'
16
+ end
17
+ end
18
+
8
19
  describe '#step_definitions_path' do
9
20
  it 'returns a default' do
10
21
  subject[:step_definitions_path].must_be_kind_of String
@@ -42,4 +53,32 @@ describe Spinach::Config do
42
53
  subject[:failure_exceptions].must_include RuntimeError
43
54
  end
44
55
  end
56
+
57
+ describe '#config_path' do
58
+ it 'returns a default' do
59
+ subject[:config_path].must_equal 'config/spinach.yml'
60
+ end
61
+
62
+ it 'can be overwritten' do
63
+ subject[:config_path] = 'my_config_file.yml'
64
+ subject[:config_path].must_equal 'my_config_file.yml'
65
+ end
66
+ end
67
+
68
+ describe '#parse_from_file' do
69
+ before do
70
+ subject[:config_path] = 'a_path'
71
+ YAML.stubs(:load_file).returns({support_path: 'my_path', config_path: 'another_path'})
72
+ subject.parse_from_file
73
+ end
74
+
75
+ it 'sets the options' do
76
+ subject[:support_path].must_equal 'my_path'
77
+ end
78
+
79
+ it "doesn't set the config_path option" do
80
+ subject[:config_path].must_equal 'a_path'
81
+ end
82
+ end
83
+
45
84
  end
@@ -15,18 +15,9 @@ describe Spinach::DSL do
15
15
  step_executed = true
16
16
  end
17
17
 
18
- @feature.new.execute_step('I say goodbye')
18
+ @feature.new.execute(stub(name: 'I say goodbye'))
19
19
  step_executed.must_equal true
20
20
  end
21
-
22
- it 'returns step source location' do
23
- @feature.When('I say goodbye') do
24
- 'You say hello'
25
- end
26
-
27
- @feature.new.execute_step('I say goodbye').first.must_include '/dsl_test.rb'
28
- @feature.new.execute_step('I say goodbye').last.must_be_kind_of Fixnum
29
- end
30
21
  end
31
22
 
32
23
  describe '#When, #Then, #And, #But' do
@@ -50,5 +41,16 @@ describe Spinach::DSL do
50
41
  @feature.new.name.must_equal "A cool feature"
51
42
  end
52
43
  end
44
+
45
+ describe '#step_location_for' do
46
+ it 'returns step source location' do
47
+ @feature.When('I say goodbye') do
48
+ 'You say hello'
49
+ end
50
+
51
+ @feature.new.step_location_for('I say goodbye').first.must_include '/dsl_test.rb'
52
+ @feature.new.step_location_for('I say goodbye').last.must_be_kind_of Fixnum
53
+ end
54
+ end
53
55
  end
54
56
  end
@@ -31,16 +31,16 @@ describe Spinach::FeatureSteps do
31
31
  end.new
32
32
  end
33
33
 
34
- describe 'execute_step' do
34
+ describe 'execute' do
35
35
  it 'runs defined step correctly' do
36
- feature.execute_step('I go to the toilet')
36
+ feature.execute(stub(name: 'I go to the toilet'))
37
37
 
38
38
  feature.pee.must_equal true
39
39
  end
40
40
 
41
41
  it 'raises an exception if step is not defined' do
42
42
  proc {
43
- feature.execute_step 'I am lost'
43
+ feature.execute(stub(name: 'I am lost'))
44
44
  }.must_raise Spinach::StepNotDefinedException
45
45
  end
46
46
  end
@@ -0,0 +1,6 @@
1
+ require 'test_helper'
2
+
3
+ module Spinach
4
+ describe Feature do
5
+ end
6
+ end
@@ -1,8 +1,8 @@
1
1
  require_relative '../../test_helper'
2
2
 
3
- describe "minitest suite" do
3
+ describe "minitest framework" do
4
4
  before do
5
- require_relative '../../../lib/spinach/suites/minitest'
5
+ require_relative '../../../lib/spinach/frameworks/minitest'
6
6
  end
7
7
 
8
8
  it "adds MiniTest::Assertion into the failure exceptions" do
@@ -4,81 +4,41 @@ require_relative '../../../lib/spinach/generators'
4
4
  module Spinach::Generators
5
5
  describe FeatureGenerator do
6
6
  subject do
7
- FeatureGenerator.new(data)
7
+ FeatureGenerator.new(feature)
8
8
  end
9
9
 
10
- let(:data) do
11
- Spinach::Parser.new("
12
- Feature: Cheezburger can I has
13
- Scenario: Some Lulz
14
- Given I haz a sad
15
- When I get some lulz
16
- Then I haz a happy
17
- Scenario: Some sad
18
- Given I haz a happy
19
- When I get some lulz
20
- Then I am OMG ROFLMAO").parse
10
+ let(:feature) do
11
+ Spinach::Parser.new("""
12
+ Feature: Cheezburger can I has
13
+ Background:
14
+ Given I liek cheezburger
15
+ Scenario: Some Lulz
16
+ Given I haz a sad
17
+ When I get some lulz
18
+ Then I haz a happy
19
+ Scenario: Some sad
20
+ Given I haz a happy
21
+ When I get some lulz
22
+ Then I am OMG ROFLMAO""").parse
21
23
  end
22
24
 
23
25
  describe "#name" do
24
- it "returns the scenario name" do
26
+ it "returns the feature name" do
25
27
  subject.name.must_equal 'Cheezburger can I has'
26
28
  end
27
-
28
- it "returns nil if no name present" do
29
- data['name'] = nil
30
- subject.name.must_equal nil
31
- end
32
29
  end
33
30
 
34
31
  describe "#steps" do
35
32
  it "returns a correct number different steps for this data" do
36
- subject.steps.length.must_equal 4
37
- end
38
-
39
- describe "includes the correct steps" do
40
- it "includes 'Given I haz a sad'" do
41
- subject.steps.any?{ |step|
42
- (step['keyword'] == 'Given') && (step['name'] == 'I haz a sad')
43
- }.must_equal true
44
- end
45
-
46
- it "includes 'When I get some lulz'" do
47
- subject.steps.any?{ |step|
48
- (step['keyword'] == 'When') && (step['name'] == 'I get some lulz')
49
- }.must_equal true
50
- end
51
-
52
- it "includes 'Then I has a happy'" do
53
- subject.steps.any?{ |step|
54
- (step['keyword'] == 'Then') && (step['name'] == 'I haz a happy')
55
- }.must_equal true
56
- end
57
-
58
- it "does not include 'Given I haz a happy'" do
59
- subject.steps.any?{ |step|
60
- (step['keyword'] == 'Given') && (step['name'] == 'I haz a happy')
61
- }.must_equal false
62
- end
63
-
64
- it "includes 'Then I am OMG ROFLMAO'" do
65
- subject.steps.any?{ |step|
66
- (step['keyword'] == 'Then') && (step['name'] == 'I am OMG ROFLMAO')
67
- }.must_equal true
68
- end
33
+ subject.steps.length.must_equal 5
69
34
  end
70
35
  end
71
36
 
72
37
  describe "#generate" do
73
38
  it "generates an entire feature_steps class definition" do
74
39
  result = subject.generate
75
- klass = eval(result)
76
- feature_runner = Spinach::Runner::FeatureRunner.new(stub_everything)
77
- feature_runner.stubs(data: data)
78
- error_count = 0
79
- CheezburgerCanIHas.any_instance.
80
- expects(:raise).with("step not implemented").times(6).returns(nil)
81
- feature_runner.run.must_equal true
40
+ result.must_match /Given 'I haz a sad' do/
41
+ result.must_match /raise 'step not implemented'/
82
42
  end
83
43
  end
84
44
 
@@ -4,11 +4,11 @@ require_relative '../../../lib/spinach/generators'
4
4
  module Spinach::Generators
5
5
  describe StepGenerator do
6
6
  subject do
7
- StepGenerator.new(data)
7
+ StepGenerator.new(step)
8
8
  end
9
9
 
10
- let(:data) do
11
- {'keyword' => 'Given', 'name' => "I has a sad"}
10
+ let(:step) do
11
+ stub(keyword: 'Given', name: 'I has a sad')
12
12
  end
13
13
 
14
14
  describe "#generate" do
@@ -6,16 +6,18 @@ describe Spinach::Generators do
6
6
  end
7
7
 
8
8
  let(:data) do
9
- Spinach::Parser.new("
10
- Feature: Cheezburger can I has
11
- Scenario: Some Lulz
12
- Given I haz a sad
13
- When I get some lulz
14
- Then I haz a happy
15
- Scenario: Some sad
16
- Given I haz a happy
17
- When I get some lulz
18
- Then I am OMG ROFLMAO").parse
9
+ Spinach::Parser.new("""
10
+ Feature: Cheezburger can I has
11
+ Background:
12
+ Given I liek cheezburger
13
+ Scenario: Some Lulz
14
+ Given I haz a sad
15
+ When I get some lulz
16
+ Then I haz a happy
17
+ Scenario: Some sad
18
+ Given I haz a happy
19
+ When I get some lulz
20
+ Then I am OMG ROFLMAO""").parse
19
21
  end
20
22
 
21
23
  describe "#bind" do
@@ -48,6 +48,14 @@ describe Spinach::Hookable do
48
48
  subject.run_hook(:before_save, 1, 2)
49
49
  array.must_equal [1, 2]
50
50
  end
51
+
52
+ it "yields to hook block even if nothing is hooked" do
53
+ called = false
54
+ subject.run_hook(:before_save) do
55
+ called = true
56
+ end
57
+ called.must_equal true
58
+ end
51
59
  end
52
60
 
53
61
  describe "#reset_hooks" do
@@ -7,7 +7,7 @@ describe Spinach::Hooks do
7
7
 
8
8
  describe "hooks" do
9
9
  %w{before_run after_run before_feature after_feature on_undefined_feature
10
- before_scenario after_scenario before_step after_step on_successful_step
10
+ before_scenario around_scenario after_scenario before_step after_step on_successful_step
11
11
  on_failed_step on_error_step on_undefined_step on_skipped_step}.each do |callback|
12
12
  describe "#{callback}" do
13
13
  it "responds to #{callback}" do
@@ -26,11 +26,10 @@ describe Spinach::Hooks do
26
26
  end
27
27
  end
28
28
  end
29
+
29
30
  describe "#on_tag" do
30
- let(:data) do
31
- {
32
- 'tags' => [{'name' => '@javascript'}, {'name' => '@capture'}]
33
- }
31
+ let(:scenario) do
32
+ stub(tags: ['javascript', 'capture'])
34
33
  end
35
34
 
36
35
  it "calls the block if the scenario includes the tag" do
@@ -38,7 +37,7 @@ describe Spinach::Hooks do
38
37
  subject.on_tag('javascript') do
39
38
  assertion = true
40
39
  end
41
- subject.run_before_scenario(data)
40
+ subject.run_before_scenario(scenario)
42
41
  assertion.must_equal true
43
42
  end
44
43
 
@@ -47,7 +46,7 @@ describe Spinach::Hooks do
47
46
  subject.on_tag('screenshot') do
48
47
  assertion = true
49
48
  end
50
- subject.run_before_scenario(data)
49
+ subject.run_before_scenario(scenario)
51
50
  assertion.wont_equal true
52
51
  end
53
52
  end
@@ -0,0 +1,173 @@
1
+ require 'test_helper'
2
+
3
+ module Spinach
4
+ class Parser
5
+ describe Visitor do
6
+ let(:feature) { Feature.new }
7
+ let(:visitor) { Visitor.new }
8
+
9
+ describe '#visit' do
10
+ it 'makes ast accept self' do
11
+ ast = stub('AST')
12
+ ast.expects(:accept).with(visitor)
13
+
14
+ visitor.visit(ast)
15
+ end
16
+
17
+ it 'returns the feature' do
18
+ ast = stub_everything
19
+ visitor.instance_variable_set(:@feature, feature)
20
+ visitor.visit(ast).must_equal feature
21
+ end
22
+ end
23
+
24
+ describe '#visit_Feature' do
25
+ before do
26
+ @background = stub_everything
27
+ @scenarios = [stub_everything, stub_everything, stub_everything]
28
+ @node = stub(scenarios: @scenarios, name: 'Go shopping', background: @background)
29
+ end
30
+
31
+ it 'sets the name' do
32
+ visitor.visit_Feature(@node)
33
+ visitor.feature.name.must_equal 'Go shopping'
34
+ end
35
+
36
+ it 'iterates over its children' do
37
+ @scenarios.each do |scenario|
38
+ scenario.expects(:accept).with visitor
39
+ end
40
+
41
+ visitor.visit_Feature(@node)
42
+ end
43
+ end
44
+
45
+ describe '#visit_Scenario' do
46
+ before do
47
+ @steps = [stub_everything, stub_everything, stub_everything]
48
+ @tags = [stub_everything, stub_everything, stub_everything]
49
+ @node = stub(
50
+ tags: @tags,
51
+ steps: @steps,
52
+ name: 'Go shopping on Saturday morning',
53
+ line: 3
54
+ )
55
+ end
56
+
57
+ it 'adds the scenario to the feature' do
58
+ visitor.visit_Scenario(@node)
59
+ visitor.feature.scenarios.length.must_equal 1
60
+ end
61
+
62
+ it 'sets the name' do
63
+ visitor.visit_Scenario(@node)
64
+ visitor.feature.scenarios.first.name.must_equal 'Go shopping on Saturday morning'
65
+ end
66
+
67
+ it 'sets the line' do
68
+ visitor.visit_Scenario(@node)
69
+ visitor.feature.scenarios.first.line.must_equal 3
70
+ end
71
+
72
+ it 'sets the tags' do
73
+ @tags.each do |step|
74
+ step.expects(:accept).with visitor
75
+ end
76
+ visitor.visit_Scenario(@node)
77
+ end
78
+
79
+ it 'iterates over its children' do
80
+ @steps.each do |step|
81
+ step.expects(:accept).with visitor
82
+ end
83
+ visitor.visit_Scenario(@node)
84
+ end
85
+
86
+ end
87
+
88
+ describe '#visit_Background' do
89
+ before do
90
+ @steps = [stub_everything, stub_everything, stub_everything]
91
+ @node = stub(
92
+ steps: @steps,
93
+ line: 3
94
+ )
95
+ end
96
+
97
+ it 'adds the background to the feature' do
98
+ visitor.visit_Background(@node)
99
+ visitor.feature.background.must_be_kind_of Background
100
+ end
101
+
102
+ it 'sets the line' do
103
+ visitor.visit_Background(@node)
104
+ visitor.feature.background.line.must_equal 3
105
+ end
106
+
107
+ it 'iterates over its children' do
108
+ @steps.each do |step|
109
+ step.expects(:accept).with visitor
110
+ end
111
+ visitor.visit_Background(@node)
112
+ end
113
+
114
+ it 'visits the background' do
115
+ visitor.visit_Background(@node)
116
+ end
117
+ end
118
+
119
+ describe '#visit_Tag' do
120
+ it 'adds the tag to the current scenario' do
121
+ tags = ['tag1', 'tag2', 'tag3']
122
+ scenario = stub(tags: tags)
123
+ visitor.instance_variable_set(:@current_scenario, scenario)
124
+
125
+ visitor.visit_Tag(stub(name: 'tag4'))
126
+ scenario.tags.must_equal ['tag1', 'tag2', 'tag3', 'tag4']
127
+ end
128
+ end
129
+
130
+ describe '#visit_Step' do
131
+ before do
132
+ @node = stub(name: 'Baz', line: 3, keyword: 'Given')
133
+ @steps = [stub(name: 'Foo'), stub(name: 'Bar')]
134
+ end
135
+
136
+ it 'adds the step to the step set' do
137
+ step_set = stub(steps: @steps)
138
+ visitor.instance_variable_set(:@current_step_set, step_set)
139
+
140
+ visitor.visit_Step(@node)
141
+ step_set.steps.length.must_equal 3
142
+ end
143
+
144
+ it 'sets the name' do
145
+ step_set = stub(steps: [])
146
+ visitor.instance_variable_set(:@current_step_set, step_set)
147
+
148
+ visitor.visit_Step(@node)
149
+
150
+ step_set.steps.first.name.must_equal 'Baz'
151
+ end
152
+
153
+ it 'sets the keyword' do
154
+ step_set = stub(steps: [])
155
+ visitor.instance_variable_set(:@current_step_set, step_set)
156
+
157
+ visitor.visit_Step(@node)
158
+
159
+ step_set.steps.first.keyword.must_equal 'Given'
160
+ end
161
+
162
+ it 'sets the line' do
163
+ step_set = stub(steps: [])
164
+ visitor.instance_variable_set(:@current_step_set, step_set)
165
+
166
+ visitor.visit_Step(@node)
167
+
168
+ step_set.steps.first.line.must_equal 3
169
+ end
170
+ end
171
+ end
172
+ end
173
+ end