spinach 0.0.2 → 0.0.4

Sign up to get free protection for your applications and to get access to all the features.
@@ -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