turnip 1.0.0 → 1.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.
- data/.gitignore +1 -0
- data/.travis.yml +3 -0
- data/README.md +14 -24
- data/examples/scenario_outline_table_substitution.feature +12 -0
- data/lib/turnip.rb +1 -1
- data/lib/turnip/builder.rb +13 -3
- data/lib/turnip/capybara.rb +0 -2
- data/lib/turnip/define.rb +6 -3
- data/lib/turnip/execute.rb +11 -3
- data/lib/turnip/rspec.rb +14 -6
- data/lib/turnip/step_definition.rb +10 -2
- data/lib/turnip/version.rb +1 -1
- data/spec/builder_spec.rb +19 -0
- data/spec/{define_and_execute.rb → define_and_execute_spec.rb} +32 -0
- data/spec/integration_spec.rb +1 -1
- data/spec/step_definition_spec.rb +5 -1
- data/spec/table_spec.rb +6 -0
- metadata +27 -11
data/.gitignore
CHANGED
data/.travis.yml
CHANGED
data/README.md
CHANGED
@@ -1,6 +1,7 @@
|
|
1
1
|
# Turnip
|
2
2
|
|
3
3
|
[](http://travis-ci.org/jnicklas/turnip)
|
4
|
+
[](https://codeclimate.com/github/jnicklas/turnip)
|
4
5
|
|
5
6
|
Turnip is a [Gherkin](https://github.com/cucumber/cucumber/wiki/Gherkin)
|
6
7
|
extension for RSpec. It allows you to write tests in Gherkin and run them
|
@@ -206,6 +207,11 @@ you were to put your steps in `spec/steps`, you could load them like this:
|
|
206
207
|
Dir.glob("spec/steps/**/*steps.rb") { |f| load f, true }
|
207
208
|
```
|
208
209
|
|
210
|
+
Before loading your `spec_helper`, Turnip also tries to load a file called
|
211
|
+
`turnip_helper` where you can setup anything specific to your turnip examples.
|
212
|
+
You might find it beneficial to load your steps from this file so that they
|
213
|
+
don't have to be loaded when you run your other tests.
|
214
|
+
|
209
215
|
### Calling steps from other steps
|
210
216
|
|
211
217
|
Since steps are Ruby methods you can call them like other Ruby methods.
|
@@ -238,36 +244,20 @@ step "the value is the magic number"
|
|
238
244
|
end
|
239
245
|
```
|
240
246
|
|
241
|
-
###
|
242
|
-
|
243
|
-
This is a more esoteric feature of Turnip, of use mostly to people who want to
|
244
|
-
do crazy stuff. You can use `send` to call any Turnip step, no matter where it
|
245
|
-
is defined or included. Additionally, the `Turnip::Execute` module has a method
|
246
|
-
called `step`, this method executes a step, given a string as it might appear
|
247
|
-
in a feature file. This is the same `step` method you used above to call steps
|
248
|
-
from within other steps.
|
247
|
+
### Methods as steps
|
249
248
|
|
250
|
-
|
249
|
+
You can mark an existing method as a step. This will make it available in your
|
250
|
+
Turnip features. For example:
|
251
251
|
|
252
252
|
``` ruby
|
253
|
-
|
254
|
-
|
255
|
-
|
256
|
-
|
257
|
-
step
|
253
|
+
module MonsterSteps
|
254
|
+
def create_monster(name)
|
255
|
+
@monster = Monster.new(:name => name)
|
256
|
+
end
|
257
|
+
step :create_monster, "there is a monster called :name"
|
258
258
|
end
|
259
|
-
|
260
|
-
monster = Monster.new
|
261
|
-
monster.step("sing a song")
|
262
|
-
monster.step("eat 1 villager")
|
263
|
-
monster.step("eat 5 villagers")
|
264
|
-
monster.send("eat :count villager(s)", 5)
|
265
259
|
```
|
266
260
|
|
267
|
-
Note that in this case `step` from `Turnip::Execute` is an *instance* method,
|
268
|
-
whereas `step` used to define the step is a *class* method, they are *not* the
|
269
|
-
same method.
|
270
|
-
|
271
261
|
## Custom step placeholders
|
272
262
|
|
273
263
|
Do you want to be more specific in what to match in your step placeholders? Do
|
@@ -0,0 +1,12 @@
|
|
1
|
+
Feature: using scenario outlines
|
2
|
+
Scenario Outline: a simple outline
|
3
|
+
Given there is a monster with hitpoints:
|
4
|
+
| hit_points |
|
5
|
+
| <hp> |
|
6
|
+
When I attack the monster and do <damage> points damage
|
7
|
+
Then the monster should be <state>
|
8
|
+
|
9
|
+
Examples:
|
10
|
+
| hp | damage | state |
|
11
|
+
| 10 | 13 | dead |
|
12
|
+
| 8 | 5 | alive |
|
data/lib/turnip.rb
CHANGED
data/lib/turnip/builder.rb
CHANGED
@@ -81,12 +81,22 @@ module Turnip
|
|
81
81
|
rows.map do |row|
|
82
82
|
Scenario.new(@raw).tap do |scenario|
|
83
83
|
scenario.steps = steps.map do |step|
|
84
|
-
new_description = step.description
|
85
|
-
|
84
|
+
new_description = substitute(step.description, headers, row)
|
85
|
+
new_extra_args = step.extra_args.map do |ea|
|
86
|
+
next ea unless ea.instance_of?(Turnip::Table)
|
87
|
+
Turnip::Table.new(ea.map {|t_row| t_row.map {|t_col| substitute(t_col, headers, row) } })
|
88
|
+
end
|
89
|
+
Step.new(new_description, new_extra_args, step.line)
|
86
90
|
end
|
87
91
|
end
|
88
92
|
end
|
89
93
|
end
|
94
|
+
|
95
|
+
private
|
96
|
+
|
97
|
+
def substitute(text, headers, row)
|
98
|
+
text.gsub(/<([^>]*)>/) { |_| Hash[headers.zip(row)][$1] }
|
99
|
+
end
|
90
100
|
end
|
91
101
|
|
92
102
|
class Step < Struct.new(:description, :extra_args, :line)
|
@@ -106,7 +116,7 @@ module Turnip
|
|
106
116
|
def build(feature_file)
|
107
117
|
Turnip::Builder.new.tap do |builder|
|
108
118
|
parser = Gherkin::Parser::Parser.new(builder, true)
|
109
|
-
parser.parse(File.read(feature_file),
|
119
|
+
parser.parse(File.read(feature_file), feature_file, 0)
|
110
120
|
end
|
111
121
|
end
|
112
122
|
end
|
data/lib/turnip/capybara.rb
CHANGED
data/lib/turnip/define.rb
CHANGED
@@ -1,9 +1,12 @@
|
|
1
1
|
module Turnip
|
2
2
|
module Define
|
3
|
-
def step(expression, &block)
|
4
|
-
|
3
|
+
def step(method_name=nil, expression, &block)
|
4
|
+
if method_name and block
|
5
|
+
raise ArgumentError, "can't specify both method name and a block for a step"
|
6
|
+
end
|
7
|
+
step = Turnip::StepDefinition.new(expression, method_name, caller.first, &block)
|
5
8
|
send(:define_method, "match: #{expression}") { |description| step.match(description) }
|
6
|
-
send(:define_method, expression, &block)
|
9
|
+
send(:define_method, expression, &block) if block
|
7
10
|
end
|
8
11
|
end
|
9
12
|
end
|
data/lib/turnip/execute.rb
CHANGED
@@ -7,9 +7,17 @@ module Turnip
|
|
7
7
|
next unless method.to_s.start_with?("match: ")
|
8
8
|
send(method.to_s, description.to_s)
|
9
9
|
end.compact
|
10
|
-
|
11
|
-
|
12
|
-
|
10
|
+
|
11
|
+
if matches.length == 0
|
12
|
+
raise Turnip::Pending, description
|
13
|
+
end
|
14
|
+
|
15
|
+
if matches.length > 1
|
16
|
+
msg = ['Ambiguous step definitions'].concat(matches.map(&:trace)).join("\r\n")
|
17
|
+
raise Turnip::Ambiguous, msg
|
18
|
+
end
|
19
|
+
|
20
|
+
send(matches.first.method_name, *(matches.first.params + extra_args))
|
13
21
|
end
|
14
22
|
end
|
15
23
|
end
|
data/lib/turnip/rspec.rb
CHANGED
@@ -12,15 +12,23 @@ module Turnip
|
|
12
12
|
module Loader
|
13
13
|
def load(*a, &b)
|
14
14
|
if a.first.end_with?('.feature')
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
end
|
15
|
+
require_if_exists 'turnip_helper'
|
16
|
+
require_if_exists 'spec_helper'
|
17
|
+
|
19
18
|
Turnip::RSpec.run(a.first)
|
20
19
|
else
|
21
20
|
super
|
22
21
|
end
|
23
22
|
end
|
23
|
+
|
24
|
+
private
|
25
|
+
|
26
|
+
def require_if_exists(filename)
|
27
|
+
require filename
|
28
|
+
rescue LoadError => e
|
29
|
+
# Don't hide LoadErrors raised in the spec helper.
|
30
|
+
raise unless e.message.include?(filename)
|
31
|
+
end
|
24
32
|
end
|
25
33
|
|
26
34
|
##
|
@@ -74,7 +82,7 @@ end
|
|
74
82
|
::RSpec::Core::Configuration.send(:include, Turnip::RSpec::Loader)
|
75
83
|
|
76
84
|
::RSpec.configure do |config|
|
77
|
-
config.include Turnip::RSpec::Execute
|
78
|
-
config.include Turnip::Steps
|
85
|
+
config.include Turnip::RSpec::Execute, turnip: true
|
86
|
+
config.include Turnip::Steps, turnip: true
|
79
87
|
config.pattern << ",**/*.feature"
|
80
88
|
end
|
@@ -2,12 +2,20 @@ module Turnip
|
|
2
2
|
class StepDefinition
|
3
3
|
class Match < Struct.new(:step_definition, :params, :block)
|
4
4
|
def expression; step_definition.expression; end
|
5
|
+
def method_name; step_definition.method_name; end
|
6
|
+
def called_from; step_definition.called_from; end
|
7
|
+
|
8
|
+
def trace
|
9
|
+
trace = %{ - "#{expression}" (#{called_from})}
|
10
|
+
end
|
5
11
|
end
|
6
12
|
|
7
|
-
attr_reader :expression, :block
|
13
|
+
attr_reader :expression, :block, :method_name, :called_from
|
8
14
|
|
9
|
-
def initialize(expression, &block)
|
15
|
+
def initialize(expression, method_name=nil, called_from=nil, &block)
|
10
16
|
@expression = expression
|
17
|
+
@method_name = method_name || expression
|
18
|
+
@called_from = called_from
|
11
19
|
@block = block
|
12
20
|
end
|
13
21
|
|
data/lib/turnip/version.rb
CHANGED
data/spec/builder_spec.rb
CHANGED
@@ -27,4 +27,23 @@ describe Turnip::Builder do
|
|
27
27
|
])
|
28
28
|
end
|
29
29
|
end
|
30
|
+
|
31
|
+
context "with example tables in scenario outlines" do
|
32
|
+
let(:feature_file) { File.expand_path('../examples/scenario_outline_table_substitution.feature', File.dirname(__FILE__)) }
|
33
|
+
let(:builder) { Turnip::Builder.build(feature_file) }
|
34
|
+
let(:feature) { builder.features.first }
|
35
|
+
|
36
|
+
it "replaces placeholders in tables in steps" do
|
37
|
+
feature.scenarios[0].steps.map(&:description).should eq([
|
38
|
+
"there is a monster with hitpoints:",
|
39
|
+
"I attack the monster and do 13 points damage",
|
40
|
+
"the monster should be dead"
|
41
|
+
])
|
42
|
+
table = feature.scenarios[0].steps[0].extra_args.find {|a| a.instance_of?(Turnip::Table)}
|
43
|
+
table.hashes[0]['hit_points'].should == '10'
|
44
|
+
table = feature.scenarios[1].steps[0].extra_args.find {|a| a.instance_of?(Turnip::Table)}
|
45
|
+
table.hashes[0]['hit_points'].should == '8'
|
46
|
+
end
|
47
|
+
|
48
|
+
end
|
30
49
|
end
|
@@ -19,6 +19,22 @@ describe Turnip::Execute do
|
|
19
19
|
obj.send("a :test step", "cool").should == "COOL"
|
20
20
|
end
|
21
21
|
|
22
|
+
it "can use an existing method as a step" do
|
23
|
+
mod.module_eval do
|
24
|
+
def a_test_step(test)
|
25
|
+
test.upcase
|
26
|
+
end
|
27
|
+
end
|
28
|
+
mod.step(:a_test_step, "a :test step")
|
29
|
+
obj.step("a cool step").should == "COOL"
|
30
|
+
end
|
31
|
+
|
32
|
+
it "raises an argument error when both method name and block given" do
|
33
|
+
expect do
|
34
|
+
mod.step(:a_test_step, "a :test step") { "foo" }
|
35
|
+
end.to raise_error(ArgumentError)
|
36
|
+
end
|
37
|
+
|
22
38
|
it "sends in extra arg from a builder step" do
|
23
39
|
mod.step("a :test step") { |test, foo| test.upcase + foo }
|
24
40
|
obj.step("a cool step", "foo").should == "COOLfoo"
|
@@ -35,4 +51,20 @@ describe Turnip::Execute do
|
|
35
51
|
mod.step("a :test step") { |test, foo| test.upcase + foo }
|
36
52
|
obj.step(builder_step).should == "COOLfoo"
|
37
53
|
end
|
54
|
+
|
55
|
+
it "defines ambiguous steps and run a matching step" do
|
56
|
+
mod.step("an ambiguous step") {}
|
57
|
+
mod.step("an :ambiguous step") {}
|
58
|
+
expect {
|
59
|
+
obj.step("an ambiguous step")
|
60
|
+
}.to raise_error(Turnip::Ambiguous)
|
61
|
+
end
|
62
|
+
|
63
|
+
it "shows useful information on the ambiguous steps" do
|
64
|
+
mod.step("an ambiguous step") {}
|
65
|
+
mod.step("an :ambiguous step") {}
|
66
|
+
expect {
|
67
|
+
obj.step("an ambiguous step")
|
68
|
+
}.to raise_error(Turnip::Ambiguous, %r{(ambiguous).*(define_and_execute_spec.rb)})
|
69
|
+
end
|
38
70
|
end
|
data/spec/integration_spec.rb
CHANGED
@@ -11,7 +11,7 @@ describe 'The CLI', :type => :integration do
|
|
11
11
|
end
|
12
12
|
|
13
13
|
it "prints out failures and successes" do
|
14
|
-
@result.should include('
|
14
|
+
@result.should include('35 examples, 3 failures, 5 pending')
|
15
15
|
end
|
16
16
|
|
17
17
|
it "includes features in backtraces" do
|
@@ -1,3 +1,5 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
1
3
|
describe Turnip::StepDefinition do
|
2
4
|
let(:all_steps) { [] }
|
3
5
|
|
@@ -31,9 +33,11 @@ describe Turnip::StepDefinition do
|
|
31
33
|
|
32
34
|
it "can reuse the same custom placeholder multiple times" do
|
33
35
|
Turnip::Placeholder.stub(:resolve).with(:count).and_return(/\d+/)
|
36
|
+
Turnip::Placeholder.stub(:apply).with(:count, "3").and_return(3)
|
37
|
+
Turnip::Placeholder.stub(:apply).with(:count, "2").and_return(2)
|
34
38
|
step = Turnip::StepDefinition.new(":count monsters and :count knights") {}
|
35
39
|
match = step.match("3 monsters and 2 knights")
|
36
|
-
match.params.should eq([
|
40
|
+
match.params.should eq([3, 2])
|
37
41
|
end
|
38
42
|
|
39
43
|
it "does search for the same custom placeholder several times" do
|
data/spec/table_spec.rb
CHANGED
@@ -8,6 +8,11 @@ describe Turnip::Table do
|
|
8
8
|
it 'returns the raw table' do
|
9
9
|
table.raw.should == [['foo', 'bar'], ['quox', '42']]
|
10
10
|
end
|
11
|
+
|
12
|
+
it 'reflects changes in the raw table' do
|
13
|
+
table.raw[1][1] = '55'
|
14
|
+
table.raw.should == [['foo', 'bar'], ['quox', '55']]
|
15
|
+
end
|
11
16
|
end
|
12
17
|
|
13
18
|
describe '#to_a' do
|
@@ -71,4 +76,5 @@ describe Turnip::Table do
|
|
71
76
|
table.map(&:first).should == ['moo', 'quox']
|
72
77
|
end
|
73
78
|
end
|
79
|
+
|
74
80
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: turnip
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.1.0
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,11 +9,11 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2012-
|
12
|
+
date: 2012-11-26 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: rspec
|
16
|
-
requirement:
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
17
17
|
none: false
|
18
18
|
requirements:
|
19
19
|
- - ~>
|
@@ -21,10 +21,15 @@ dependencies:
|
|
21
21
|
version: '2.0'
|
22
22
|
type: :runtime
|
23
23
|
prerelease: false
|
24
|
-
version_requirements:
|
24
|
+
version_requirements: !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
26
|
+
requirements:
|
27
|
+
- - ~>
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: '2.0'
|
25
30
|
- !ruby/object:Gem::Dependency
|
26
31
|
name: gherkin
|
27
|
-
requirement:
|
32
|
+
requirement: !ruby/object:Gem::Requirement
|
28
33
|
none: false
|
29
34
|
requirements:
|
30
35
|
- - ! '>='
|
@@ -32,10 +37,15 @@ dependencies:
|
|
32
37
|
version: '2.5'
|
33
38
|
type: :runtime
|
34
39
|
prerelease: false
|
35
|
-
version_requirements:
|
40
|
+
version_requirements: !ruby/object:Gem::Requirement
|
41
|
+
none: false
|
42
|
+
requirements:
|
43
|
+
- - ! '>='
|
44
|
+
- !ruby/object:Gem::Version
|
45
|
+
version: '2.5'
|
36
46
|
- !ruby/object:Gem::Dependency
|
37
47
|
name: rake
|
38
|
-
requirement:
|
48
|
+
requirement: !ruby/object:Gem::Requirement
|
39
49
|
none: false
|
40
50
|
requirements:
|
41
51
|
- - ! '>='
|
@@ -43,7 +53,12 @@ dependencies:
|
|
43
53
|
version: '0'
|
44
54
|
type: :development
|
45
55
|
prerelease: false
|
46
|
-
version_requirements:
|
56
|
+
version_requirements: !ruby/object:Gem::Requirement
|
57
|
+
none: false
|
58
|
+
requirements:
|
59
|
+
- - ! '>='
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0'
|
47
62
|
description: Provides the ability to define steps and run Gherkin files from with
|
48
63
|
RSpec
|
49
64
|
email:
|
@@ -66,6 +81,7 @@ files:
|
|
66
81
|
- examples/multiline_string.feature
|
67
82
|
- examples/pending.feature
|
68
83
|
- examples/scenario_outline.feature
|
84
|
+
- examples/scenario_outline_table_substitution.feature
|
69
85
|
- examples/simple_feature.feature
|
70
86
|
- examples/step_calling.feature
|
71
87
|
- examples/steps/alignment_steps.rb
|
@@ -95,7 +111,7 @@ files:
|
|
95
111
|
- lib/turnip/table.rb
|
96
112
|
- lib/turnip/version.rb
|
97
113
|
- spec/builder_spec.rb
|
98
|
-
- spec/
|
114
|
+
- spec/define_and_execute_spec.rb
|
99
115
|
- spec/dsl_spec.rb
|
100
116
|
- spec/integration_spec.rb
|
101
117
|
- spec/placeholder_spec.rb
|
@@ -123,13 +139,13 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
123
139
|
version: '0'
|
124
140
|
requirements: []
|
125
141
|
rubyforge_project: turnip
|
126
|
-
rubygems_version: 1.8.
|
142
|
+
rubygems_version: 1.8.24
|
127
143
|
signing_key:
|
128
144
|
specification_version: 3
|
129
145
|
summary: Gherkin extension for RSpec
|
130
146
|
test_files:
|
131
147
|
- spec/builder_spec.rb
|
132
|
-
- spec/
|
148
|
+
- spec/define_and_execute_spec.rb
|
133
149
|
- spec/dsl_spec.rb
|
134
150
|
- spec/integration_spec.rb
|
135
151
|
- spec/placeholder_spec.rb
|