spinach 0.0.2 → 0.0.4

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,19 @@
1
+ require 'active_support/inflector/methods'
2
+
3
+ module Spinach
4
+ # A module to offer common helpers
5
+ module Support
6
+ # A helper to camelize string that proxies ActiveSupport#camelize
7
+ #
8
+ # @param [String] name
9
+ #
10
+ # @returns [String]
11
+ #
12
+ # @example
13
+ # Spinach::Support.camelize('User authentication')
14
+ # => 'UserAuthentication'
15
+ def self.camelize(name)
16
+ ActiveSupport::Inflector.camelize(name.to_s.downcase.strip.squeeze(' ').gsub(' ','_'))
17
+ end
18
+ end
19
+ end
@@ -1,3 +1,3 @@
1
1
  module Spinach
2
- VERSION = "0.0.2"
2
+ VERSION = "0.0.4"
3
3
  end
data/lib/spinach.rb CHANGED
@@ -1,11 +1,14 @@
1
1
  require_relative 'spinach/version'
2
2
  require_relative 'spinach/config'
3
+ require_relative 'spinach/support'
4
+ require_relative 'spinach/exceptions'
3
5
  require_relative 'spinach/runner'
4
6
  require_relative 'spinach/parser'
5
7
  require_relative 'spinach/dsl'
6
8
  require_relative 'spinach/feature'
7
9
  require_relative 'spinach/reporter'
8
10
 
11
+
9
12
  # Spinach is a BDD framework in top of gherkin. Its main goals are:
10
13
  # * No magic: All features are implemented using actual classes.
11
14
  # * Reusability: Steps are methods, so they can be put inside modules.
@@ -35,8 +38,10 @@ module Spinach
35
38
  # the feature name
36
39
  #
37
40
  def self.find_feature(name)
41
+ klass = Spinach::Support.camelize(name)
38
42
  @@features.detect do |feature|
39
- feature.feature_name.to_s == name.to_s
40
- end
43
+ feature.feature_name.to_s == name.to_s ||
44
+ feature.name == klass
45
+ end || raise(Spinach::FeatureNotFoundException, [klass, name])
41
46
  end
42
47
  end
data/spinach.gemspec CHANGED
@@ -2,7 +2,7 @@
2
2
  require File.expand_path('../lib/spinach/version', __FILE__)
3
3
 
4
4
  Gem::Specification.new do |gem|
5
- gem.authors = ["Josep Jaume Rey", "Josep M. Bach", "Oriol Gual"]
5
+ gem.authors = ["Josep Jaume Rey", "Josep M. Bach", "Oriol Gual", "Marc Divins Castellvi"]
6
6
  gem.email = ["info@codegram.com"]
7
7
  gem.description = %q{Spinach is a BDD framework on top of gherkin}
8
8
  gem.summary = %q{Spinach is a BDD framework on top of gherkin}
@@ -11,11 +11,14 @@ Gem::Specification.new do |gem|
11
11
  gem.add_runtime_dependency 'gherkin'
12
12
  gem.add_runtime_dependency 'minitest'
13
13
  gem.add_runtime_dependency 'colorize'
14
+ gem.add_runtime_dependency 'activesupport'
14
15
  gem.add_development_dependency 'purdytest'
15
16
  gem.add_development_dependency 'rake'
16
17
  gem.add_development_dependency 'mocha'
17
18
  gem.add_development_dependency 'sinatra'
18
19
  gem.add_development_dependency 'capybara'
20
+ gem.add_development_dependency 'aruba'
21
+ gem.add_development_dependency 'pry'
19
22
 
20
23
  gem.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
21
24
  gem.files = `git ls-files`.split("\n")
@@ -3,30 +3,34 @@ require_relative '../test_helper'
3
3
  describe Spinach::DSL do
4
4
  before do
5
5
  @feature = Class.new do
6
- extend Spinach::DSL
6
+ include Spinach::DSL
7
7
  end
8
8
  end
9
- %w{When Given Then And But}.each do |connector|
10
- describe "##{connector}" do
11
- it "should define a method with the step name" do
12
- @feature.send(connector, "I say goodbye") do
13
- "You say hello"
9
+
10
+ describe 'class methods' do
11
+ describe "#When" do
12
+ it 'defines a method with the step name' do
13
+ @feature.When('I say goodbye') do
14
+ 'You say hello'
14
15
  end
15
- @feature.new.send("#{connector} I say goodbye").must_equal "You say hello"
16
+
17
+ @feature.new.send('I say goodbye').must_equal 'You say hello'
16
18
  end
17
19
  end
18
- end
19
- describe "#Given, #Then, #And, #But" do
20
- it "should be #When aliases" do
21
- %w{Given Then And But}.each do |m|
22
- @feature.must_respond_to m
20
+
21
+ describe '#When, #Then, #And, #But' do
22
+ it 'are #Given aliases' do
23
+ %w{When Then And But}.each do |method|
24
+ @feature.must_respond_to method
25
+ end
23
26
  end
24
27
  end
25
- end
26
- describe "#feature" do
27
- it "should set the name for this feature" do
28
- @feature.feature("User salutes")
29
- @feature.feature_name.must_equal "User salutes"
28
+
29
+ describe '#feature' do
30
+ it 'sets the name for this feature' do
31
+ @feature.feature('User salutes')
32
+ @feature.feature_name.must_equal 'User salutes'
33
+ end
30
34
  end
31
35
  end
32
36
  end
@@ -2,21 +2,51 @@ require_relative '../test_helper'
2
2
 
3
3
  describe Spinach::Feature do
4
4
  describe "ancestors" do
5
- it "should include minitest helpers" do
5
+ it 'includes minitest helpers' do
6
6
  Spinach::Feature.ancestors.must_include MiniTest::Assertions
7
7
  end
8
- it "should be extended by the DSL" do
9
- (class << Spinach::Feature; self; end).ancestors.must_include Spinach::DSL
8
+
9
+ it 'is extended by the DSL' do
10
+ Spinach::Feature.ancestors.must_include Spinach::DSL
11
+ end
12
+ end
13
+
14
+ describe 'class methods' do
15
+ describe '#inherited' do
16
+ it 'registers any feature subclass' do
17
+ @feature1 = Class.new(Spinach::Feature)
18
+ @feature2 = Class.new(Spinach::Feature)
19
+ @feature3 = Class.new
20
+
21
+ Spinach.features.must_include @feature1
22
+ Spinach.features.must_include @feature2
23
+ Spinach.features.wont_include @feature3
24
+ end
10
25
  end
11
26
  end
12
- describe "#inherited" do
13
- it "should register any feature subclass" do
14
- @feature1 = Class.new(Spinach::Feature)
15
- @feature2 = Class.new(Spinach::Feature)
16
- @feature3 = Class.new
17
- Spinach.features.must_include @feature1
18
- Spinach.features.must_include @feature2
19
- Spinach.features.wont_include @feature3
27
+
28
+ describe 'instance methods' do
29
+ before do
30
+ @feature = Class.new(Spinach::Feature) do
31
+ When 'I go to the toilet' do
32
+ @pee = true
33
+ end
34
+ attr_reader :pee
35
+ end.new
36
+ end
37
+
38
+ describe 'execute_step' do
39
+ it 'runs defined step correctly' do
40
+ @feature.execute_step('I go to the toilet')
41
+
42
+ @feature.pee.must_equal true
43
+ end
44
+
45
+ it 'raises an exception if step is not defined' do
46
+ proc {
47
+ @feature.execute_step 'I am lost'
48
+ }.must_raise Spinach::StepNotDefinedException
49
+ end
20
50
  end
21
51
  end
22
52
  end
@@ -0,0 +1,128 @@
1
+ # encoding: utf-8
2
+
3
+ require_relative '../../test_helper'
4
+
5
+ describe Spinach::Reporter::Stdout do
6
+ before do
7
+ @reporter = Spinach::Reporter::Stdout.new
8
+ end
9
+
10
+ describe "#feature" do
11
+ it "outputs a feature name" do
12
+ out = capture_stdout do
13
+ @reporter.feature "User authentication"
14
+ end
15
+ out.string.must_include "\nFeature: User authentication"
16
+ end
17
+ end
18
+
19
+ describe "#scenario" do
20
+ it "outputs a scenario name" do
21
+ out = capture_stdout do
22
+ @reporter.scenario "User logs in"
23
+ end
24
+ out.string.must_include " Scenario: User logs in"
25
+ end
26
+ end
27
+
28
+ describe "#step" do
29
+ before do
30
+ @feature = stubs(name: "Some cool feature")
31
+ end
32
+ describe "when succeeding" do
33
+ it "outputs the step name" do
34
+ out = capture_stdout do
35
+ @reporter.step "Given", "I say goodbye", :success
36
+ end
37
+ out.string.must_include "✔"
38
+ out.string.must_include "Given I say goodbye"
39
+ end
40
+ end
41
+
42
+ describe "when undefined" do
43
+ it "outputs the step name with a question mark" do
44
+ out = capture_stdout do
45
+ @reporter.step "Given", "I say goodbye", :undefined_step
46
+ end
47
+ out.string.must_include "?"
48
+ out.string.must_include "Given I say goodbye"
49
+ end
50
+ end
51
+
52
+ describe "when failing" do
53
+ it "outputs the step name with a failure mark" do
54
+ out = capture_stdout do
55
+ @reporter.step "Given", "I say goodbye", :failure
56
+ end
57
+ out.string.must_include "✘"
58
+ out.string.must_include "Given I say goodbye"
59
+ end
60
+ end
61
+
62
+ describe "when failing" do
63
+ it "outputs the step name with a failure mark" do
64
+ out = capture_stdout do
65
+ @reporter.step "Given", "I say goodbye", :error
66
+ end
67
+ out.string.must_include "!"
68
+ out.string.must_include "Given I say goodbye"
69
+ end
70
+ end
71
+
72
+ describe "when skipping" do
73
+ it "outputs the step name with a failure mark" do
74
+ out = capture_stdout do
75
+ @reporter.step "Given", "I say nothing", :skip
76
+ end
77
+ out.string.must_include "~"
78
+ out.string.must_include "Given I say nothing"
79
+ end
80
+ end
81
+ end
82
+
83
+ describe "#end" do
84
+ it "outputs a blank line" do
85
+ out = capture_stdout do
86
+ @reporter.end
87
+ end
88
+ out.string.must_include "\n"
89
+ end
90
+ end
91
+
92
+ describe "#error_summary" do
93
+ it "outputs an error summary" do
94
+ make_error = proc do |message|
95
+ stub(
96
+ message: message,
97
+ backtrace: ["foo:1", "bar:2"]
98
+ )
99
+ end
100
+
101
+ make_scenario = proc do |name|
102
+ stub(
103
+ feature_name: name,
104
+ feature: stub_everything,
105
+ name: name
106
+ )
107
+ end
108
+
109
+ errors = [
110
+ [make_error.('omg'), "some_file", "3", make_scenario.('feature')],
111
+ [make_error.('wtf'), "other_file", "9", make_scenario.('feature')],
112
+ ]
113
+
114
+ out = capture_stdout do
115
+ @reporter.error_summary(errors)
116
+ end
117
+ out.string.must_include "omg"
118
+ out.string.must_include "some_file"
119
+ out.string.must_include "(line 3)"
120
+ out.string.must_include "wtf"
121
+ out.string.must_include "other_file"
122
+ out.string.must_include "(line 9)"
123
+
124
+ out.string.must_include "foo:1"
125
+ out.string.must_include "bar:2"
126
+ end
127
+ end
128
+ end
@@ -15,13 +15,15 @@ describe Spinach::Reporter do
15
15
  end
16
16
  end
17
17
  end
18
+
18
19
  describe "#step" do
19
20
  it "raises an error" do
20
21
  Proc.new{
21
- @reporter.step("arbitrary name", :success)
22
+ @reporter.step("Given", "arbitrary name", :success)
22
23
  }.must_raise RuntimeError
23
24
  end
24
25
  end
26
+
25
27
  describe "#end" do
26
28
  it "raises an error" do
27
29
  Proc.new{
@@ -30,62 +32,5 @@ describe Spinach::Reporter do
30
32
  end
31
33
  end
32
34
  end
33
- describe Spinach::Reporter::Stdout do
34
- before do
35
- @reporter = Spinach::Reporter::Stdout.new
36
- end
37
- describe "#feature" do
38
- it "outputs a feature name" do
39
- out = capture_stdout do
40
- @reporter.feature "User authentication"
41
- end
42
- out.string.must_include "\nFeature: User authentication"
43
- end
44
- end
45
- describe "#scenario" do
46
- it "outputs a scenario name" do
47
- out = capture_stdout do
48
- @reporter.scenario "User logs in"
49
- end
50
- out.string.must_include " Scenario: User logs in"
51
- end
52
- end
53
- describe "#step" do
54
- describe "when succeeding" do
55
- it "outputs the step name" do
56
- out = capture_stdout do
57
- @reporter.step "Given I say goodbye", :success
58
- end
59
- out.string.must_include "✔"
60
- out.string.must_include "Given I say goodbye"
61
- end
62
- end
63
- describe "when failing" do
64
- it "outputs the step name with a failure mark" do
65
- out = capture_stdout do
66
- @reporter.step "Given I say goodbye", :failure
67
- end
68
- out.string.must_include "✘"
69
- out.string.must_include "Given I say goodbye"
70
- end
71
- end
72
- describe "when skipping" do
73
- it "outputs the step name with a failure mark" do
74
- out = capture_stdout do
75
- @reporter.step "Given I say nothing", :skip
76
- end
77
- out.string.must_include "~"
78
- out.string.must_include "Given I say nothing"
79
- end
80
- end
81
- end
82
- describe "#end" do
83
- it "outputs a blank line" do
84
- out = capture_stdout do
85
- @reporter.end
86
- end
87
- out.string.must_include "\n"
88
- end
89
- end
90
- end
35
+
91
36
  end
@@ -0,0 +1,108 @@
1
+ require_relative '../../test_helper'
2
+
3
+ describe Spinach::Runner::Feature do
4
+ before do
5
+ @filename = 'feature/a_cool_feature.feature'
6
+ @reporter = stub_everything
7
+ @feature = Spinach::Runner::Feature.new(@filename, @reporter)
8
+ end
9
+
10
+ describe '#initialize' do
11
+ it 'initializes the given filename' do
12
+ @feature.filename.must_equal @filename
13
+ end
14
+
15
+ it 'initializes the given reporter' do
16
+ @feature.reporter.must_equal @reporter
17
+ end
18
+
19
+ it 'initalizes the given scenario line' do
20
+ @filename = 'feature/a_cool_feature.feature:12'
21
+ @feature = Spinach::Runner::Feature.new(@filename, @reporter)
22
+
23
+ @feature.instance_variable_get(:@scenario_line).must_equal '12'
24
+ end
25
+ end
26
+
27
+ describe '#feature' do
28
+ it 'finds the feature given a feature name' do
29
+ feature = stub_everything
30
+ @feature.stubs(feature_name: 'A cool feature')
31
+ Spinach.expects(:find_feature).with('A cool feature').returns(feature)
32
+ @feature.feature
33
+ end
34
+ end
35
+
36
+ describe '#data' do
37
+ it 'returns the parsed data' do
38
+ parsed_data = {'name' => 'A cool feature'}
39
+ parser = stub(:parse => parsed_data)
40
+ Spinach::Parser.expects(:new).returns(parser)
41
+ @feature.data.must_equal parsed_data
42
+ end
43
+ end
44
+
45
+ describe '#scenarios' do
46
+ it 'returns the parsed scenarios' do
47
+ @feature.stubs(data: {'elements' => [1, 2, 3]})
48
+ @feature.scenarios.must_equal [1,2,3]
49
+ end
50
+ end
51
+
52
+ describe '#run' do
53
+ before do
54
+ @feature.stubs(data: {
55
+ 'name' => 'A cool feature',
56
+ 'elements' => [{'keyword'=>'Scenario', 'name'=>'Basic guess', 'line'=>6, 'description'=>'', 'type'=>'scenario'},
57
+ {'keyword'=>'Scenario', 'name'=>'Basic guess II', 'line'=>12, 'description'=>'', 'type'=>'scenario'},
58
+ {'keyword'=>'Scenario', 'name'=>'Basic guess III', 'line'=>18, 'description'=>'', 'type'=>'scenario'}]
59
+ })
60
+ @feature.stubs(feature: stub_everything)
61
+ end
62
+
63
+ it 'reports' do
64
+ Spinach::Runner::Scenario.stubs(new: stub_everything)
65
+
66
+ @reporter.expects(:feature).with('A cool feature')
67
+ @feature.run
68
+ end
69
+
70
+ it 'calls the steps as expected' do
71
+ seq = sequence('feature')
72
+ 3.times do
73
+ @feature.feature.expects(:before).in_sequence(seq)
74
+ Spinach::Runner::Scenario.
75
+ expects(:new).
76
+ returns(stub_everything).
77
+ in_sequence(seq)
78
+ @feature.feature.expects(:after).in_sequence(seq)
79
+ end
80
+ @feature.run
81
+ end
82
+
83
+ it 'calls only the given scenario' do
84
+ @filename = 'feature/a_cool_feature.feature:12'
85
+ @feature = Spinach::Runner::Feature.new(@filename, @reporter)
86
+ @feature.stubs(data: {
87
+ 'name' => 'A cool feature',
88
+ 'elements' => [{'keyword'=>'Scenario', 'name'=>'Basic guess', 'line'=>6, 'description'=>'', 'type'=>'scenario'},
89
+ {'keyword'=>'Scenario', 'name'=>'Basic guess II', 'line'=>12, 'description'=>'', 'type'=>'scenario'},
90
+ {'keyword'=>'Scenario', 'name'=>'Basic guess III', 'line'=>18, 'description'=>'', 'type'=>'scenario'}]
91
+ })
92
+ @feature.stubs(feature: stub_everything)
93
+
94
+ Spinach::Runner::Scenario.expects(:new).with(anything, anything, @feature.scenarios[1], anything).once.returns(stub_everything)
95
+ @feature.run
96
+ end
97
+
98
+ it "calls an error summary if there are any failures" do
99
+ failure = stub('failure')
100
+ scenario = stub(run: failure)
101
+ Spinach::Runner::Scenario.stubs(:new).returns scenario
102
+
103
+ @reporter.expects(:error_summary).with [failure, failure, failure]
104
+
105
+ @feature.run
106
+ end
107
+ end
108
+ end
@@ -0,0 +1,70 @@
1
+ require_relative '../../test_helper'
2
+
3
+ describe Spinach::Runner::Scenario do
4
+ before do
5
+ @data = {
6
+ 'name' => 'A cool scenario',
7
+ 'steps' => [
8
+ {'keyword' => 'Given', 'name' => 'I herd you like steps'},
9
+ {'keyword' => 'When', 'name' => 'I test steps'},
10
+ {'keyword' => 'Then', 'name' => 'I go step by step'}
11
+ ]
12
+ }
13
+ @feature = stub_everything
14
+ @feature_name = "My feature"
15
+ @reporter = stub_everything
16
+ @scenario = Spinach::Runner::Scenario.new(@feature_name, @feature, @data, @reporter)
17
+ end
18
+
19
+ describe '#initialize' do
20
+ it 'initializes a scenario name' do
21
+ @scenario.name.must_equal 'A cool scenario'
22
+ end
23
+
24
+ it 'lists all the steps' do
25
+ @scenario.steps.count.must_equal 3
26
+ end
27
+
28
+ it 'sets the reporter' do
29
+ @scenario.reporter.must_equal @reporter
30
+ end
31
+
32
+ it 'sets the feature' do
33
+ @scenario.feature.must_equal @feature
34
+ end
35
+ end
36
+
37
+ describe '#run' do
38
+ it 'calls the appropiate feature steps' do
39
+ @feature.expects(:execute_step).with('I herd you like steps')
40
+ @feature.expects(:execute_step).with('I test steps')
41
+ @feature.expects(:execute_step).with('I go step by step')
42
+ @scenario.run
43
+ end
44
+
45
+ describe 'rescues exceptions' do
46
+ it 'rescues a MiniTest::Assertion' do
47
+ @feature.expects(:execute_step).raises(MiniTest::Assertion)
48
+ @reporter.expects(:step).with(anything, anything, :failure)
49
+ @scenario.run
50
+ end
51
+
52
+ it 'rescues a Spinach::StepNotDefinedException' do
53
+ @feature.expects(:execute_step).raises(Spinach::StepNotDefinedException.new('foo', 'bar'))
54
+ @reporter.expects(:step).with(anything, anything, :undefined_step)
55
+ @scenario.run
56
+ end
57
+
58
+ it 'rescues any other error' do
59
+ @feature.expects(:execute_step).raises
60
+ @reporter.expects(:step).with(anything, anything, :error)
61
+ @scenario.run
62
+ end
63
+
64
+ it 'runs a step' do
65
+ @reporter.expects(:step).with(anything, anything, :success).times(3)
66
+ @scenario.run
67
+ end
68
+ end
69
+ end
70
+ end