turnip 0.1.1 → 0.2.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/README.md +46 -6
- data/{spec/fixture → examples}/ambiguous.feature +0 -0
- data/{spec/fixture → examples}/backgrounds.feature +0 -0
- data/{spec/fixture → examples}/interpolation.feature +0 -0
- data/examples/multiline_string.feature +8 -0
- data/{spec/fixture → examples}/pending.feature +0 -0
- data/examples/scenario_outline.feature +10 -0
- data/{spec/fixture → examples}/simple_feature.feature +0 -0
- data/examples/steps.rb +102 -0
- data/examples/steps_for.feature +10 -0
- data/examples/table.feature +8 -0
- data/{spec/fixture → examples}/tags.feature +0 -0
- data/examples/with_comments.feature +12 -0
- data/lib/turnip.rb +35 -6
- data/lib/turnip/builder.rb +46 -4
- data/lib/turnip/dsl.rb +15 -4
- data/lib/turnip/step_definition.rb +45 -22
- data/lib/turnip/table.rb +28 -0
- data/lib/turnip/version.rb +1 -1
- data/spec/builder_spec.rb +30 -0
- data/spec/dsl_spec.rb +54 -0
- data/spec/integration_spec.rb +16 -0
- data/spec/spec_helper.rb +3 -51
- data/spec/step_definition_spec.rb +118 -0
- data/spec/table_spec.rb +48 -0
- metadata +30 -21
- data/lib/turnip/rspec.rb +0 -5
- data/lib/turnip/run.rb +0 -27
data/.gitignore
CHANGED
data/README.md
CHANGED
@@ -5,12 +5,6 @@ extension for RSpec. It allows you to write tests in Gherkin and run them
|
|
5
5
|
through your RSpec environment. Basically you can write cucumber features in
|
6
6
|
RSpec.
|
7
7
|
|
8
|
-
## DISCLAIMER, READ THIS!!!
|
9
|
-
|
10
|
-
Turnip is a proof of concept, there are currently VERY FEW TESTS, and there is
|
11
|
-
a lot of cucumber's syntax it does NOT support. There are currently no tables,
|
12
|
-
multiline string or scenario outlines.
|
13
|
-
|
14
8
|
## Installation
|
15
9
|
|
16
10
|
Install the gem
|
@@ -92,6 +86,16 @@ Given there is a monster called Jonas
|
|
92
86
|
And there is a monster called "Jonas Nicklas"
|
93
87
|
```
|
94
88
|
|
89
|
+
You can also specify alternative words and optional parts of words, like this:
|
90
|
+
|
91
|
+
``` ruby
|
92
|
+
step "there is/are :count monster(s)" do |count|
|
93
|
+
@monsters = Array.new(count) { Monster.new }
|
94
|
+
end
|
95
|
+
```
|
96
|
+
|
97
|
+
That will match both "there is X monster" or "there are X monsters".
|
98
|
+
|
95
99
|
## Defining placeholders
|
96
100
|
|
97
101
|
But what if you want to be more specific in what to match in those
|
@@ -135,6 +139,42 @@ end
|
|
135
139
|
These regular expressions must not use anchors, e.g. `^` or `$`. They may not
|
136
140
|
contain named capture groups, e.g. `(?<color>blue|green)`.
|
137
141
|
|
142
|
+
## Specific steps
|
143
|
+
|
144
|
+
Sometimes you might want to limit where steps are matched. Turnip allows you to
|
145
|
+
do this, through the `:for` option on your steps:
|
146
|
+
|
147
|
+
``` ruby
|
148
|
+
step "I do it", :for => :interface do
|
149
|
+
click_link('Do it')
|
150
|
+
end
|
151
|
+
|
152
|
+
step "I do it", :for => :database do
|
153
|
+
Do.it!
|
154
|
+
end
|
155
|
+
```
|
156
|
+
|
157
|
+
Not you can use tags in your feature files to decide which step is going to get
|
158
|
+
run:
|
159
|
+
|
160
|
+
``` cucumber
|
161
|
+
@interface
|
162
|
+
Scenario: do it through the interface
|
163
|
+
|
164
|
+
@database
|
165
|
+
Scenario: do it through the database
|
166
|
+
```
|
167
|
+
|
168
|
+
If you have many steps for the same tag, you can use the `steps_for` helper:
|
169
|
+
|
170
|
+
``` ruby
|
171
|
+
steps_for :interface do
|
172
|
+
step "I do it" do
|
173
|
+
...
|
174
|
+
end
|
175
|
+
end
|
176
|
+
```
|
177
|
+
|
138
178
|
## Using with Capybara
|
139
179
|
|
140
180
|
Just require `turnip/capybara`, either in your `spec_helper` or by
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
@@ -0,0 +1,10 @@
|
|
1
|
+
Feature: using scenario outlines
|
2
|
+
Scenario Outline: a simple outline
|
3
|
+
Given there is a monster with <hp> hitpoints
|
4
|
+
When I attack the monster and do <damage> points damage
|
5
|
+
Then the monster should be <state>
|
6
|
+
|
7
|
+
Examples:
|
8
|
+
| hp | damage | state |
|
9
|
+
| 10 | 13 | dead |
|
10
|
+
| 8 | 5 | alive |
|
File without changes
|
data/examples/steps.rb
ADDED
@@ -0,0 +1,102 @@
|
|
1
|
+
step "there is a monster" do
|
2
|
+
@monster = 1
|
3
|
+
end
|
4
|
+
|
5
|
+
step "there is a strong monster" do
|
6
|
+
@monster = 2
|
7
|
+
end
|
8
|
+
|
9
|
+
step "I attack it" do
|
10
|
+
@monster -= 1
|
11
|
+
end
|
12
|
+
|
13
|
+
step "it should die" do
|
14
|
+
@monster.should eq(0)
|
15
|
+
end
|
16
|
+
|
17
|
+
step "this is ambiguous" do
|
18
|
+
end
|
19
|
+
|
20
|
+
step "this is ambiguous" do
|
21
|
+
end
|
22
|
+
|
23
|
+
step "there is a monster called :name" do |name|
|
24
|
+
@monster_name = name
|
25
|
+
end
|
26
|
+
|
27
|
+
step 'it should be called "John Smith"' do
|
28
|
+
@monster_name.should == "John Smith"
|
29
|
+
end
|
30
|
+
|
31
|
+
step 'it should be called "John"' do
|
32
|
+
@monster_name.should == "John"
|
33
|
+
end
|
34
|
+
|
35
|
+
step "there are :count monkeys with :color hair" do |count, color|
|
36
|
+
@monkeys = Array.new(count) { color }
|
37
|
+
end
|
38
|
+
|
39
|
+
step "there should be 3 monkeys with blue hair" do
|
40
|
+
@monkeys.should == [:blue, :blue, :blue]
|
41
|
+
end
|
42
|
+
|
43
|
+
step "there is a monster with :count hitpoints" do |count|
|
44
|
+
@monster = count
|
45
|
+
end
|
46
|
+
|
47
|
+
step "I attack the monster and do :count points damage" do |count|
|
48
|
+
@monster -= count
|
49
|
+
end
|
50
|
+
|
51
|
+
step "the monster should be alive" do
|
52
|
+
@monster.should > 0
|
53
|
+
end
|
54
|
+
|
55
|
+
step "the monster should be dead" do
|
56
|
+
@monster.should <= 0
|
57
|
+
end
|
58
|
+
|
59
|
+
step "there are the following monsters:" do |table|
|
60
|
+
@monsters = {}
|
61
|
+
table.hashes.each do |hash|
|
62
|
+
@monsters[hash['Name']] = hash['Hitpoints'].to_i
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
step ":name should have :count hitpoints" do |name, count|
|
67
|
+
@monsters[name].should eq(count.to_i)
|
68
|
+
end
|
69
|
+
|
70
|
+
step "the monster sings the following song" do |song|
|
71
|
+
@song = song
|
72
|
+
end
|
73
|
+
|
74
|
+
step "the song should have :count lines" do |count|
|
75
|
+
@song.to_s.split("\n").length.should eq(count)
|
76
|
+
end
|
77
|
+
|
78
|
+
step "the monster has an alignment", :for => :evil do
|
79
|
+
@alignment = 'Evil'
|
80
|
+
end
|
81
|
+
|
82
|
+
steps_for :neutral do
|
83
|
+
step "the monster has an alignment" do
|
84
|
+
@alignment = 'Neutral'
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
step "that alignment should be :alignment" do |alignment|
|
89
|
+
@alignment.should eq(alignment)
|
90
|
+
end
|
91
|
+
|
92
|
+
placeholder :count do
|
93
|
+
match /\d+/ do |count|
|
94
|
+
count.to_i
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
placeholder :color do
|
99
|
+
match /blue|green|red/ do |color|
|
100
|
+
color.to_sym
|
101
|
+
end
|
102
|
+
end
|
File without changes
|
@@ -0,0 +1,12 @@
|
|
1
|
+
# Hi.
|
2
|
+
Feature: some feature
|
3
|
+
Comments can be (almost) everywhere.
|
4
|
+
# And another comment
|
5
|
+
|
6
|
+
Scenario: some scenario
|
7
|
+
# Yet another one.
|
8
|
+
Given there is a monster
|
9
|
+
When I attack it
|
10
|
+
Then it should die
|
11
|
+
# Oh my, comments are everywhere.
|
12
|
+
# Thank you for reading.
|
data/lib/turnip.rb
CHANGED
@@ -2,18 +2,47 @@ require "gherkin"
|
|
2
2
|
require "gherkin/formatter/tag_count_formatter"
|
3
3
|
|
4
4
|
require "turnip/version"
|
5
|
-
require "turnip/loader"
|
6
|
-
require "turnip/builder"
|
7
|
-
require "turnip/run"
|
8
|
-
require "turnip/step_definition"
|
9
|
-
require "turnip/placeholder"
|
10
5
|
require "turnip/dsl"
|
11
|
-
require "turnip/rspec"
|
12
6
|
|
13
7
|
module Turnip
|
8
|
+
autoload :Loader, 'turnip/loader'
|
9
|
+
autoload :Builder, 'turnip/builder'
|
10
|
+
autoload :StepDefinition, 'turnip/step_definition'
|
11
|
+
autoload :Placeholder, 'turnip/placeholder'
|
12
|
+
autoload :Table, 'turnip/table'
|
13
|
+
|
14
14
|
class << self
|
15
15
|
attr_accessor :type
|
16
|
+
|
17
|
+
def run(content)
|
18
|
+
Turnip::Builder.build(content).features.each do |feature|
|
19
|
+
describe feature.name, feature.metadata_hash do
|
20
|
+
feature.backgrounds.each do |background|
|
21
|
+
before do
|
22
|
+
background.steps.each do |step|
|
23
|
+
Turnip::StepDefinition.execute(self, step)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
feature.scenarios.each do |scenario|
|
28
|
+
it scenario.name, scenario.metadata_hash do
|
29
|
+
scenario.steps.each do |step|
|
30
|
+
Turnip::StepDefinition.execute(self, step)
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
16
37
|
end
|
17
38
|
end
|
18
39
|
|
19
40
|
Turnip.type = :turnip
|
41
|
+
|
42
|
+
RSpec::Core::Configuration.send(:include, Turnip::Loader)
|
43
|
+
|
44
|
+
RSpec.configure do |config|
|
45
|
+
config.pattern << ",**/*.feature"
|
46
|
+
end
|
47
|
+
|
48
|
+
self.extend Turnip::DSL
|
data/lib/turnip/builder.rb
CHANGED
@@ -49,7 +49,7 @@ module Turnip
|
|
49
49
|
include Tags
|
50
50
|
include Name
|
51
51
|
|
52
|
-
|
52
|
+
attr_accessor :steps
|
53
53
|
|
54
54
|
def initialize(raw)
|
55
55
|
@raw = raw
|
@@ -57,16 +57,46 @@ module Turnip
|
|
57
57
|
end
|
58
58
|
end
|
59
59
|
|
60
|
-
class
|
60
|
+
class ScenarioOutline
|
61
|
+
include Tags
|
61
62
|
include Name
|
62
63
|
|
64
|
+
attr_reader :steps
|
65
|
+
|
63
66
|
def initialize(raw)
|
64
67
|
@raw = raw
|
68
|
+
@steps = []
|
65
69
|
end
|
70
|
+
|
71
|
+
def to_scenarios(examples)
|
72
|
+
rows = examples.rows.map(&:cells)
|
73
|
+
headers = rows.shift
|
74
|
+
rows.map do |row|
|
75
|
+
Scenario.new(@raw).tap do |scenario|
|
76
|
+
scenario.steps = steps.map do |step|
|
77
|
+
new_description = step.description.gsub(/<([^>]*)>/) { |_| Hash[headers.zip(row)][$1] }
|
78
|
+
Step.new(new_description, step.extra_arg)
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
class Step < Struct.new(:description, :extra_arg)
|
66
86
|
end
|
67
87
|
|
68
88
|
attr_reader :features
|
69
89
|
|
90
|
+
class << self
|
91
|
+
def build(content)
|
92
|
+
Turnip::Builder.new.tap do |builder|
|
93
|
+
formatter = Gherkin::Formatter::TagCountFormatter.new(builder, {})
|
94
|
+
parser = Gherkin::Parser::Parser.new(formatter, true, "root", false)
|
95
|
+
parser.parse(content, nil, 0)
|
96
|
+
end
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
70
100
|
def initialize
|
71
101
|
@features = []
|
72
102
|
end
|
@@ -86,9 +116,21 @@ module Turnip
|
|
86
116
|
@current_feature.scenarios << @current_step_context
|
87
117
|
end
|
88
118
|
|
119
|
+
def scenario_outline(outline)
|
120
|
+
@current_step_context = ScenarioOutline.new(outline)
|
121
|
+
end
|
122
|
+
|
123
|
+
def examples(examples)
|
124
|
+
@current_feature.scenarios.push(*@current_step_context.to_scenarios(examples))
|
125
|
+
end
|
126
|
+
|
89
127
|
def step(step)
|
90
|
-
|
91
|
-
|
128
|
+
if step.doc_string
|
129
|
+
extra_arg = step.doc_string.value
|
130
|
+
elsif step.rows
|
131
|
+
extra_arg = Turnip::Table.new(step.rows.map { |row| row.cells(&:value) })
|
132
|
+
end
|
133
|
+
@current_step_context.steps << Step.new(step.name, extra_arg)
|
92
134
|
end
|
93
135
|
|
94
136
|
def eof
|
data/lib/turnip/dsl.rb
CHANGED
@@ -1,7 +1,20 @@
|
|
1
1
|
module Turnip
|
2
2
|
module DSL
|
3
|
-
|
4
|
-
|
3
|
+
class << self
|
4
|
+
attr_accessor :current_taggings
|
5
|
+
end
|
6
|
+
|
7
|
+
def step(description, options={}, &block)
|
8
|
+
if Turnip::DSL.current_taggings
|
9
|
+
options[:for] = [options[:for], *Turnip::DSL.current_taggings].compact.flatten
|
10
|
+
end
|
11
|
+
Turnip::StepDefinition.add(description, options, &block)
|
12
|
+
end
|
13
|
+
|
14
|
+
def steps_for(*taggings)
|
15
|
+
Turnip::DSL.current_taggings = [taggings, *Turnip::DSL.current_taggings].compact.flatten
|
16
|
+
yield
|
17
|
+
Turnip::DSL.current_taggings = nil
|
5
18
|
end
|
6
19
|
|
7
20
|
def placeholder(name, &block)
|
@@ -9,5 +22,3 @@ module Turnip
|
|
9
22
|
end
|
10
23
|
end
|
11
24
|
end
|
12
|
-
|
13
|
-
self.extend Turnip::DSL
|
@@ -1,62 +1,85 @@
|
|
1
1
|
module Turnip
|
2
2
|
class StepDefinition
|
3
|
-
class Match < Struct.new(:params, :block)
|
3
|
+
class Match < Struct.new(:step_definition, :params, :block)
|
4
|
+
def expression; step_definition.expression; end
|
5
|
+
def options; step_definition.options; end
|
6
|
+
end
|
7
|
+
|
4
8
|
class Pending < StandardError; end
|
5
9
|
class Ambiguous < StandardError; end
|
6
10
|
|
7
|
-
attr_reader :expression, :block
|
11
|
+
attr_reader :expression, :block, :options
|
8
12
|
|
9
13
|
class << self
|
10
|
-
def execute(context,
|
11
|
-
match = find(description)
|
12
|
-
|
14
|
+
def execute(context, step)
|
15
|
+
match = find(step.description, context.example.metadata)
|
16
|
+
params = match.params
|
17
|
+
params << step.extra_arg if step.extra_arg
|
18
|
+
context.instance_exec(*params, &match.block)
|
13
19
|
rescue Pending
|
14
|
-
context.pending "the step '#{description}' is not implemented"
|
20
|
+
context.pending "the step '#{step.description}' is not implemented"
|
15
21
|
end
|
16
22
|
|
17
|
-
def add(expression, &block)
|
18
|
-
|
23
|
+
def add(expression, options={}, &block)
|
24
|
+
all << StepDefinition.new(expression, options, &block)
|
19
25
|
end
|
20
26
|
|
21
|
-
def find(description)
|
22
|
-
found =
|
23
|
-
step.match(description)
|
27
|
+
def find(description, metadata={})
|
28
|
+
found = all.map do |step|
|
29
|
+
step.match(description, metadata)
|
24
30
|
end.compact
|
25
31
|
raise Pending, description if found.length == 0
|
26
32
|
raise Ambiguous, description if found.length > 1
|
27
33
|
found[0]
|
28
34
|
end
|
29
35
|
|
30
|
-
def
|
31
|
-
@
|
36
|
+
def all
|
37
|
+
@all ||= []
|
32
38
|
end
|
33
39
|
end
|
34
40
|
|
35
|
-
def initialize(expression, &block)
|
41
|
+
def initialize(expression, options={}, &block)
|
36
42
|
@expression = expression
|
37
43
|
@block = block
|
44
|
+
@options = options
|
38
45
|
end
|
39
46
|
|
40
47
|
def regexp
|
41
48
|
@regexp ||= compile_regexp
|
42
49
|
end
|
43
50
|
|
44
|
-
def match(description)
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
51
|
+
def match(description, metadata={})
|
52
|
+
if matches_metadata?(metadata)
|
53
|
+
result = description.match(regexp)
|
54
|
+
if result
|
55
|
+
params = result.captures
|
56
|
+
result.names.each_with_index do |name, index|
|
57
|
+
params[index] = Turnip::Placeholder.apply(name.to_sym, params[index])
|
58
|
+
end
|
59
|
+
Match.new(self, params, block)
|
50
60
|
end
|
51
|
-
Match.new(params, block)
|
52
61
|
end
|
53
62
|
end
|
54
63
|
|
55
64
|
protected
|
56
65
|
|
66
|
+
def matches_metadata?(metadata)
|
67
|
+
not options[:for] or [options[:for]].flatten.any? { |option| metadata.has_key?(option) }
|
68
|
+
end
|
69
|
+
|
70
|
+
OPTIONAL_WORD_REGEXP = /(\\\s)?\\\(([^)]+)\\\)(\\\s)?/
|
71
|
+
PLACEHOLDER_REGEXP = /:([\w]+)/
|
72
|
+
ALTERNATIVE_WORD_REGEXP = /(\w+)((\/\w+)+)/
|
73
|
+
|
57
74
|
def compile_regexp
|
58
75
|
regexp = Regexp.escape(expression)
|
59
|
-
regexp
|
76
|
+
regexp.gsub!(OPTIONAL_WORD_REGEXP) do |_|
|
77
|
+
[$1, $2, $3].compact.map { |m| "(#{m})?" }.join
|
78
|
+
end
|
79
|
+
regexp.gsub!(ALTERNATIVE_WORD_REGEXP) do |_|
|
80
|
+
"(#{$1}#{$2.tr('/', '|')})"
|
81
|
+
end
|
82
|
+
regexp.gsub!(PLACEHOLDER_REGEXP) do |_|
|
60
83
|
"(?<#{$1}>#{Placeholder.resolve($1.to_sym)})"
|
61
84
|
end
|
62
85
|
Regexp.new("^#{regexp}$")
|
data/lib/turnip/table.rb
ADDED
@@ -0,0 +1,28 @@
|
|
1
|
+
module Turnip
|
2
|
+
class Table
|
3
|
+
attr_reader :raw
|
4
|
+
alias_method :to_a, :raw
|
5
|
+
|
6
|
+
include Enumerable
|
7
|
+
|
8
|
+
def initialize(raw)
|
9
|
+
@raw = raw
|
10
|
+
end
|
11
|
+
|
12
|
+
def headers
|
13
|
+
@raw.first
|
14
|
+
end
|
15
|
+
|
16
|
+
def rows
|
17
|
+
@raw.drop(1)
|
18
|
+
end
|
19
|
+
|
20
|
+
def hashes
|
21
|
+
rows.map { |row| Hash[headers.zip(row)] }
|
22
|
+
end
|
23
|
+
|
24
|
+
def each
|
25
|
+
@raw.each { |row| yield(row) }
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
data/lib/turnip/version.rb
CHANGED
@@ -0,0 +1,30 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Turnip::Builder do
|
4
|
+
context "with scenario outlines" do
|
5
|
+
let(:gherkin) { File.read(File.expand_path('../examples/scenario_outline.feature', File.dirname(__FILE__))) }
|
6
|
+
let(:builder) { Turnip::Builder.build(gherkin) }
|
7
|
+
let(:feature) { builder.features.first }
|
8
|
+
|
9
|
+
|
10
|
+
it "extracts scenarios" do
|
11
|
+
feature.scenarios.map(&:name).should eq([
|
12
|
+
'a simple outline',
|
13
|
+
'a simple outline'
|
14
|
+
])
|
15
|
+
end
|
16
|
+
|
17
|
+
it "replaces placeholders in steps" do
|
18
|
+
feature.scenarios[0].steps.map(&:description).should eq([
|
19
|
+
"there is a monster with 10 hitpoints",
|
20
|
+
"I attack the monster and do 13 points damage",
|
21
|
+
"the monster should be dead"
|
22
|
+
])
|
23
|
+
feature.scenarios[1].steps.map(&:description).should eq([
|
24
|
+
"there is a monster with 8 hitpoints",
|
25
|
+
"I attack the monster and do 5 points damage",
|
26
|
+
"the monster should be alive"
|
27
|
+
])
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
data/spec/dsl_spec.rb
ADDED
@@ -0,0 +1,54 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Turnip::DSL do
|
4
|
+
before do
|
5
|
+
@context = stub
|
6
|
+
@context.extend(Turnip::DSL)
|
7
|
+
end
|
8
|
+
|
9
|
+
describe '#step' do
|
10
|
+
it 'adds a step to the list of step definitions' do
|
11
|
+
Turnip::StepDefinition.should_receive(:add).with('this is a :thing test', {})
|
12
|
+
@context.step 'this is a :thing test'
|
13
|
+
end
|
14
|
+
|
15
|
+
it 'sends through options' do
|
16
|
+
Turnip::StepDefinition.should_receive(:add).with('foo', {:for => [:monkey]})
|
17
|
+
@context.step 'foo', :for => [:monkey]
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
describe '#steps_for' do
|
22
|
+
it 'executes the given block and adds steps with for set' do
|
23
|
+
Turnip::StepDefinition.should_receive(:add).with('foo', {:for => [:gorilla]})
|
24
|
+
@context.steps_for :gorilla do
|
25
|
+
@context.step 'foo'
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
it 'combines step for option and block options' do
|
30
|
+
Turnip::StepDefinition.should_receive(:add).with('foo', {:for => [:a, :b, :gorilla]})
|
31
|
+
@context.steps_for :gorilla do
|
32
|
+
@context.step 'foo', :for => [:a, :b]
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
it 'can be nested' do
|
37
|
+
Turnip::StepDefinition.should_receive(:add).with('foo', {:for => [:c, :b, :a]})
|
38
|
+
@context.steps_for :a do
|
39
|
+
@context.steps_for :b do
|
40
|
+
@context.step 'foo', :for => :c
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
describe '#placeholder' do
|
47
|
+
it 'adds a placeholder to the list of placeholders' do
|
48
|
+
@context.placeholder :quox do
|
49
|
+
match(/foo/) { 'bar' }
|
50
|
+
end
|
51
|
+
Turnip::Placeholder.apply(:quox, 'foo').should == 'bar'
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe 'The CLI', :type => :integration do
|
4
|
+
before do
|
5
|
+
@result = %x(rspec -fs examples/*.feature)
|
6
|
+
end
|
7
|
+
|
8
|
+
it "shows the correct description" do
|
9
|
+
@result.should include('A simple feature')
|
10
|
+
@result.should include('is a simple feature')
|
11
|
+
end
|
12
|
+
|
13
|
+
it "prints out failures and successes" do
|
14
|
+
@result.should include('16 examples, 1 failure, 1 pending')
|
15
|
+
end
|
16
|
+
end
|
data/spec/spec_helper.rb
CHANGED
@@ -1,53 +1,5 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
step "there is a strong monster" do
|
6
|
-
@monster = 2
|
7
|
-
end
|
8
|
-
|
9
|
-
step "I attack it" do
|
10
|
-
@monster -= 1
|
11
|
-
end
|
12
|
-
|
13
|
-
step "it should die" do
|
14
|
-
@monster.should eq(0)
|
15
|
-
end
|
16
|
-
|
17
|
-
step "this is ambiguous" do
|
18
|
-
end
|
19
|
-
|
20
|
-
step "this is ambiguous" do
|
21
|
-
end
|
22
|
-
|
23
|
-
step "there is a monster called :name" do |name|
|
24
|
-
@monster_name = name
|
25
|
-
end
|
26
|
-
|
27
|
-
step 'it should be called "John Smith"' do
|
28
|
-
@monster_name.should == "John Smith"
|
29
|
-
end
|
30
|
-
|
31
|
-
step 'it should be called "John"' do
|
32
|
-
@monster_name.should == "John"
|
33
|
-
end
|
34
|
-
|
35
|
-
step "there are :count monkeys with :color hair" do |count, color|
|
36
|
-
@monkeys = Array.new(count) { color }
|
37
|
-
end
|
38
|
-
|
39
|
-
step "there should be 3 monkeys with blue hair" do
|
40
|
-
@monkeys.should == [:blue, :blue, :blue]
|
41
|
-
end
|
42
|
-
|
43
|
-
placeholder :count do
|
44
|
-
match /\d+/ do |count|
|
45
|
-
count.to_i
|
46
|
-
end
|
47
|
-
end
|
48
|
-
|
49
|
-
placeholder :color do
|
50
|
-
match /blue|green|red/ do |color|
|
51
|
-
color.to_sym
|
1
|
+
RSpec.configure do |config|
|
2
|
+
config.before(:each, :turnip => true) do
|
3
|
+
require File.expand_path('../examples/steps', File.dirname(__FILE__))
|
52
4
|
end
|
53
5
|
end
|
@@ -0,0 +1,118 @@
|
|
1
|
+
describe Turnip::StepDefinition do
|
2
|
+
after do
|
3
|
+
Turnip::StepDefinition.all.clear
|
4
|
+
end
|
5
|
+
|
6
|
+
describe ".add" do
|
7
|
+
it "adds a step definition to the list of definitions" do
|
8
|
+
Turnip::StepDefinition.add "this is a test"
|
9
|
+
Turnip::StepDefinition.all.first.expression.should eq("this is a test")
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
describe ".find" do
|
14
|
+
it "returns a step definition that matches the description" do
|
15
|
+
Turnip::StepDefinition.add "there are :count monsters"
|
16
|
+
Turnip::StepDefinition.find("there are 23 monsters").expression.should eq("there are :count monsters")
|
17
|
+
end
|
18
|
+
|
19
|
+
it "respects the for option" do
|
20
|
+
Turnip::StepDefinition.add "alignment", :for => [:evil]
|
21
|
+
Turnip::StepDefinition.add "alignment", :for => [:good]
|
22
|
+
Turnip::StepDefinition.find("alignment", :evil => true, :bad => true).options[:for].should == [:evil]
|
23
|
+
end
|
24
|
+
|
25
|
+
it "raises an error if the match is ambiguous" do
|
26
|
+
Turnip::StepDefinition.add "there are :count monsters"
|
27
|
+
Turnip::StepDefinition.add "there are 23 monsters"
|
28
|
+
expect { Turnip::StepDefinition.find("there are 23 monsters") }.to raise_error(Turnip::StepDefinition::Ambiguous)
|
29
|
+
end
|
30
|
+
|
31
|
+
it "raises an error if there is no match" do
|
32
|
+
expect { Turnip::StepDefinition.find("there are 23 monsters") }.to raise_error(Turnip::StepDefinition::Pending)
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
describe ".execute" do
|
37
|
+
it "executes a step in the given context" do
|
38
|
+
context = stub(:example => stub(:metadata => {}))
|
39
|
+
Turnip::StepDefinition.add("there are :count monsters") { @testing = 123 }
|
40
|
+
Turnip::StepDefinition.execute(context, stub(:description => "there are 23 monsters", :extra_arg => nil))
|
41
|
+
context.instance_variable_get(:@testing).should == 123
|
42
|
+
end
|
43
|
+
|
44
|
+
it "tells the context that the step is pending" do
|
45
|
+
context = stub(:example => stub(:metadata => {}))
|
46
|
+
context.should_receive(:pending).with("the step 'there are 23 monsters' is not implemented")
|
47
|
+
Turnip::StepDefinition.execute(context, stub(:description => "there are 23 monsters", :extra_arg => nil))
|
48
|
+
end
|
49
|
+
|
50
|
+
it "sends along arguments" do
|
51
|
+
context = stub(:example => stub(:metadata => {}))
|
52
|
+
Turnip::StepDefinition.add("there are :count monsters") { |count| @testing = count.to_i }
|
53
|
+
Turnip::StepDefinition.execute(context, stub(:description => "there are 23 monsters", :extra_arg => nil))
|
54
|
+
context.instance_variable_get(:@testing).should == 23
|
55
|
+
end
|
56
|
+
|
57
|
+
it "sends along extra arguments" do
|
58
|
+
context = stub(:example => stub(:metadata => {}))
|
59
|
+
Turnip::StepDefinition.add("there are :count monsters") { |count, extra| @testing = extra }
|
60
|
+
Turnip::StepDefinition.execute(context, stub(:description => "there are 23 monsters", :extra_arg => 'foo'))
|
61
|
+
context.instance_variable_get(:@testing).should == 'foo'
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
describe "#match" do
|
66
|
+
it "matches a simple step" do
|
67
|
+
step = Turnip::StepDefinition.new("there are monsters") {}
|
68
|
+
step.should match("there are monsters")
|
69
|
+
step.should_not match("there are monsters around")
|
70
|
+
step.should_not match("there are people")
|
71
|
+
end
|
72
|
+
|
73
|
+
it "matches placeholders" do
|
74
|
+
Turnip::Placeholder.stub(:resolve).with(:count).and_return(/\d+/)
|
75
|
+
step = Turnip::StepDefinition.new("there are :count monsters") {}
|
76
|
+
step.should match("there are 4 monsters")
|
77
|
+
step.should match("there are 324 monsters")
|
78
|
+
step.should_not match("there are no monsters")
|
79
|
+
end
|
80
|
+
|
81
|
+
it "matches alternative words" do
|
82
|
+
step = Turnip::StepDefinition.new("there is/are monsters") {}
|
83
|
+
step.should match("there are monsters")
|
84
|
+
step.should match("there is monsters")
|
85
|
+
step.should_not match("there be monsters")
|
86
|
+
end
|
87
|
+
|
88
|
+
it "matches several alternative words" do
|
89
|
+
step = Turnip::StepDefinition.new("monsters are cool/nice/scary") {}
|
90
|
+
step.should match("monsters are cool")
|
91
|
+
step.should match("monsters are nice")
|
92
|
+
step.should match("monsters are scary")
|
93
|
+
step.should_not match("monsters are sexy")
|
94
|
+
end
|
95
|
+
|
96
|
+
it "matches optional parts of words" do
|
97
|
+
step = Turnip::StepDefinition.new("there is/are X monster(s)") {}
|
98
|
+
step.should match("there is X monster")
|
99
|
+
step.should_not match("there is X monsterQ")
|
100
|
+
end
|
101
|
+
|
102
|
+
it "matches optional words" do
|
103
|
+
step = Turnip::StepDefinition.new("there is a (scary) monster") {}
|
104
|
+
step.should match("there is a monster")
|
105
|
+
step.should match("there is a scary monster")
|
106
|
+
step.should_not match("there is a terrifying monster")
|
107
|
+
|
108
|
+
step = Turnip::StepDefinition.new("there is a monster (that is scary)") {}
|
109
|
+
step.should match("there is a monster that is scary")
|
110
|
+
step.should match("there is a monster")
|
111
|
+
|
112
|
+
step = Turnip::StepDefinition.new("(there is) a monster") {}
|
113
|
+
step.should match("there is a monster")
|
114
|
+
step.should match("a monster")
|
115
|
+
end
|
116
|
+
end
|
117
|
+
end
|
118
|
+
|
data/spec/table_spec.rb
ADDED
@@ -0,0 +1,48 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Turnip::Table do
|
4
|
+
describe '#raw' do
|
5
|
+
it 'returns the raw table' do
|
6
|
+
table = Turnip::Table.new([['foo', 'bar'], ['quox', '42']])
|
7
|
+
table.raw.should == [['foo', 'bar'], ['quox', '42']]
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
describe '#to_a' do
|
12
|
+
it 'returns the raw table' do
|
13
|
+
table = Turnip::Table.new([['foo', 'bar'], ['quox', '42']])
|
14
|
+
table.to_a.should == [['foo', 'bar'], ['quox', '42']]
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
describe '#headers' do
|
19
|
+
it 'returns the first row' do
|
20
|
+
table = Turnip::Table.new([['foo', 'bar'], ['quox', '42']])
|
21
|
+
table.headers.should == ['foo', 'bar']
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
describe '#rows' do
|
26
|
+
it 'returns the rows beyond the first' do
|
27
|
+
table = Turnip::Table.new([['foo', 'bar'], ['moo', '55'], ['quox', '42']])
|
28
|
+
table.rows.should == [['moo', '55'], ['quox', '42']]
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
describe '#hashes' do
|
33
|
+
it 'returns a list of hashe based on the headers' do
|
34
|
+
table = Turnip::Table.new([['foo', 'bar'], ['moo', '55'], ['quox', '42']])
|
35
|
+
table.hashes.should == [
|
36
|
+
{'foo' => 'moo', 'bar' => '55'},
|
37
|
+
{'foo' => 'quox', 'bar' => '42'}
|
38
|
+
]
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
describe '#map' do
|
43
|
+
it 'iterates over the raw table' do
|
44
|
+
table = Turnip::Table.new([['moo', '55'], ['quox', '42']])
|
45
|
+
table.map(&:first).should == ['moo', 'quox']
|
46
|
+
end
|
47
|
+
end
|
48
|
+
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: 0.
|
4
|
+
version: 0.2.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: 2011-
|
12
|
+
date: 2011-11-05 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: rspec
|
16
|
-
requirement: &
|
16
|
+
requirement: &2152642360 !ruby/object:Gem::Requirement
|
17
17
|
none: false
|
18
18
|
requirements:
|
19
19
|
- - ~>
|
@@ -21,10 +21,10 @@ dependencies:
|
|
21
21
|
version: '2.0'
|
22
22
|
type: :runtime
|
23
23
|
prerelease: false
|
24
|
-
version_requirements: *
|
24
|
+
version_requirements: *2152642360
|
25
25
|
- !ruby/object:Gem::Dependency
|
26
26
|
name: gherkin
|
27
|
-
requirement: &
|
27
|
+
requirement: &2152641940 !ruby/object:Gem::Requirement
|
28
28
|
none: false
|
29
29
|
requirements:
|
30
30
|
- - ! '>='
|
@@ -32,7 +32,7 @@ dependencies:
|
|
32
32
|
version: '0'
|
33
33
|
type: :runtime
|
34
34
|
prerelease: false
|
35
|
-
version_requirements: *
|
35
|
+
version_requirements: *2152641940
|
36
36
|
description: Provides the ability to define steps and run Gherkin files from with
|
37
37
|
RSpec
|
38
38
|
email:
|
@@ -46,24 +46,34 @@ files:
|
|
46
46
|
- Gemfile
|
47
47
|
- README.md
|
48
48
|
- Rakefile
|
49
|
+
- examples/ambiguous.feature
|
50
|
+
- examples/backgrounds.feature
|
51
|
+
- examples/interpolation.feature
|
52
|
+
- examples/multiline_string.feature
|
53
|
+
- examples/pending.feature
|
54
|
+
- examples/scenario_outline.feature
|
55
|
+
- examples/simple_feature.feature
|
56
|
+
- examples/steps.rb
|
57
|
+
- examples/steps_for.feature
|
58
|
+
- examples/table.feature
|
59
|
+
- examples/tags.feature
|
60
|
+
- examples/with_comments.feature
|
49
61
|
- lib/turnip.rb
|
50
62
|
- lib/turnip/builder.rb
|
51
63
|
- lib/turnip/capybara.rb
|
52
64
|
- lib/turnip/dsl.rb
|
53
65
|
- lib/turnip/loader.rb
|
54
66
|
- lib/turnip/placeholder.rb
|
55
|
-
- lib/turnip/rspec.rb
|
56
|
-
- lib/turnip/run.rb
|
57
67
|
- lib/turnip/step_definition.rb
|
68
|
+
- lib/turnip/table.rb
|
58
69
|
- lib/turnip/version.rb
|
59
|
-
- spec/
|
60
|
-
- spec/
|
61
|
-
- spec/
|
62
|
-
- spec/fixture/pending.feature
|
63
|
-
- spec/fixture/simple_feature.feature
|
64
|
-
- spec/fixture/tags.feature
|
70
|
+
- spec/builder_spec.rb
|
71
|
+
- spec/dsl_spec.rb
|
72
|
+
- spec/integration_spec.rb
|
65
73
|
- spec/placeholder_spec.rb
|
66
74
|
- spec/spec_helper.rb
|
75
|
+
- spec/step_definition_spec.rb
|
76
|
+
- spec/table_spec.rb
|
67
77
|
- turnip.gemspec
|
68
78
|
homepage: ''
|
69
79
|
licenses: []
|
@@ -85,16 +95,15 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
85
95
|
version: '0'
|
86
96
|
requirements: []
|
87
97
|
rubyforge_project: turnip
|
88
|
-
rubygems_version: 1.8.
|
98
|
+
rubygems_version: 1.8.10
|
89
99
|
signing_key:
|
90
100
|
specification_version: 3
|
91
101
|
summary: Gherkin extension for RSpec
|
92
102
|
test_files:
|
93
|
-
- spec/
|
94
|
-
- spec/
|
95
|
-
- spec/
|
96
|
-
- spec/fixture/pending.feature
|
97
|
-
- spec/fixture/simple_feature.feature
|
98
|
-
- spec/fixture/tags.feature
|
103
|
+
- spec/builder_spec.rb
|
104
|
+
- spec/dsl_spec.rb
|
105
|
+
- spec/integration_spec.rb
|
99
106
|
- spec/placeholder_spec.rb
|
100
107
|
- spec/spec_helper.rb
|
108
|
+
- spec/step_definition_spec.rb
|
109
|
+
- spec/table_spec.rb
|
data/lib/turnip/rspec.rb
DELETED
data/lib/turnip/run.rb
DELETED
@@ -1,27 +0,0 @@
|
|
1
|
-
module Turnip
|
2
|
-
def self.run(content)
|
3
|
-
builder = Turnip::Builder.new
|
4
|
-
formatter = Gherkin::Formatter::TagCountFormatter.new(builder, {})
|
5
|
-
parser = Gherkin::Parser::Parser.new(formatter, true, "root", false)
|
6
|
-
parser.parse(content, nil, 0)
|
7
|
-
|
8
|
-
builder.features.each do |feature|
|
9
|
-
describe feature.name, feature.metadata_hash do
|
10
|
-
feature.backgrounds.each do |background|
|
11
|
-
before do
|
12
|
-
background.steps.each do |step|
|
13
|
-
Turnip::StepDefinition.execute(self, step.name)
|
14
|
-
end
|
15
|
-
end
|
16
|
-
end
|
17
|
-
feature.scenarios.each do |scenario|
|
18
|
-
it scenario.name, scenario.metadata_hash do
|
19
|
-
scenario.steps.each do |step|
|
20
|
-
Turnip::StepDefinition.execute(self, step.name)
|
21
|
-
end
|
22
|
-
end
|
23
|
-
end
|
24
|
-
end
|
25
|
-
end
|
26
|
-
end
|
27
|
-
end
|