turnip 0.3.1 → 1.0.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/README.md +128 -166
- data/examples/autoload_steps.feature +3 -2
- data/examples/errors.feature +8 -0
- data/examples/step_calling.feature +2 -0
- data/examples/steps/alignment_steps.rb +23 -0
- data/examples/{autoload_steps.rb → steps/autoload_steps.rb} +0 -0
- data/examples/steps/backtick_steps.rb +10 -0
- data/examples/steps/dragon_steps.rb +41 -0
- data/examples/{knight_steps.rb → steps/knight_steps.rb} +3 -1
- data/examples/{more_steps.rb → steps/more_steps.rb} +0 -0
- data/examples/{step_calling_steps.rb → steps/step_calling_steps.rb} +0 -0
- data/examples/{steps.rb → steps/steps.rb} +25 -1
- data/examples/steps_for.feature +2 -2
- data/examples/steps_with_variations.feature +17 -0
- data/lib/turnip.rb +19 -34
- data/lib/turnip/builder.rb +26 -24
- data/lib/turnip/define.rb +9 -0
- data/lib/turnip/dsl.rb +11 -17
- data/lib/turnip/execute.rb +15 -0
- data/lib/turnip/rspec.rb +80 -0
- data/lib/turnip/step_definition.rb +7 -32
- data/lib/turnip/version.rb +1 -1
- data/spec/builder_spec.rb +1 -40
- data/spec/define_and_execute.rb +38 -0
- data/spec/dsl_spec.rb +36 -19
- data/spec/integration_spec.rb +5 -1
- data/spec/spec_helper.rb +1 -3
- data/spec/step_definition_spec.rb +37 -51
- metadata +25 -55
- data/examples/alignment_steps.rb +0 -7
- data/examples/backtick_steps.rb +0 -4
- data/examples/dragon_steps.rb +0 -17
- data/examples/evil_steps.rb +0 -7
- data/examples/neutral_steps.rb +0 -7
- data/examples/red_dragon_steps.rb +0 -18
- data/lib/turnip/config.rb +0 -18
- data/lib/turnip/feature_file.rb +0 -20
- data/lib/turnip/loader.rb +0 -16
- data/lib/turnip/runner_dsl.rb +0 -9
- data/lib/turnip/scenario_context.rb +0 -41
- data/lib/turnip/scenario_runner.rb +0 -35
- data/lib/turnip/step_loader.rb +0 -27
- data/lib/turnip/step_module.rb +0 -89
- data/spec/feature_file_spec.rb +0 -18
- data/spec/runner_dsl_spec.rb +0 -23
- data/spec/scenario_context_spec.rb +0 -51
- data/spec/scenario_runner_spec.rb +0 -79
- data/spec/step_loader_spec.rb +0 -29
- data/spec/step_module_spec.rb +0 -106
File without changes
|
@@ -0,0 +1,41 @@
|
|
1
|
+
require_relative "knight_steps"
|
2
|
+
|
3
|
+
module DragonSteps
|
4
|
+
include KnightSteps
|
5
|
+
|
6
|
+
attr_accessor :dragon
|
7
|
+
|
8
|
+
def dragon_attack
|
9
|
+
dragon * 10
|
10
|
+
end
|
11
|
+
|
12
|
+
step "there is a dragon" do
|
13
|
+
self.dragon = 1
|
14
|
+
end
|
15
|
+
|
16
|
+
step "the dragon attacks the knight" do
|
17
|
+
knight.attacked_for(dragon_attack)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
module RedDragonSteps
|
22
|
+
include DragonSteps
|
23
|
+
|
24
|
+
attr_accessor :red_dragon
|
25
|
+
|
26
|
+
def dragon_attack
|
27
|
+
attack = super
|
28
|
+
if red_dragon
|
29
|
+
attack + 15
|
30
|
+
else
|
31
|
+
attack
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
step "the dragon breathes fire" do
|
36
|
+
self.red_dragon = 1
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
RSpec.configure { |c| c.include DragonSteps, :dragon => true }
|
41
|
+
RSpec.configure { |c| c.include RedDragonSteps, :red_dragon => true }
|
File without changes
|
File without changes
|
@@ -17,7 +17,7 @@ end
|
|
17
17
|
step "this is ambiguous" do
|
18
18
|
end
|
19
19
|
|
20
|
-
step "this is ambiguous" do
|
20
|
+
step "this is :ambiguous" do
|
21
21
|
end
|
22
22
|
|
23
23
|
step "there is a monster called :name" do |name|
|
@@ -79,6 +79,30 @@ step "the song should have :count lines" do |count|
|
|
79
79
|
@song.to_s.split("\n").length.should eq(count)
|
80
80
|
end
|
81
81
|
|
82
|
+
step "it should be strong/tough" do
|
83
|
+
@monster.should >= 2
|
84
|
+
end
|
85
|
+
|
86
|
+
step "it should be (a) badass" do
|
87
|
+
@monster.should >= 2
|
88
|
+
end
|
89
|
+
|
90
|
+
step "it should be (a) badass" do
|
91
|
+
@monster.should >= 2
|
92
|
+
end
|
93
|
+
|
94
|
+
step "it should be terrible(st)" do
|
95
|
+
@monster.should >= 2
|
96
|
+
end
|
97
|
+
|
98
|
+
step "it (should) have/has :count (terrifying) hitpoint(s)" do |count|
|
99
|
+
@monster.should == count
|
100
|
+
end
|
101
|
+
|
102
|
+
step "raise error" do
|
103
|
+
raise "foobar"
|
104
|
+
end
|
105
|
+
|
82
106
|
placeholder :count do
|
83
107
|
match /\d+/ do |count|
|
84
108
|
count.to_i
|
data/examples/steps_for.feature
CHANGED
@@ -1,10 +1,10 @@
|
|
1
1
|
Feature: Steps for a feature
|
2
2
|
@evil
|
3
|
-
Scenario:
|
3
|
+
Scenario: Evil
|
4
4
|
Given the monster has an alignment
|
5
5
|
Then that alignment should be "Evil"
|
6
6
|
|
7
7
|
@neutral
|
8
|
-
Scenario:
|
8
|
+
Scenario: Neutral
|
9
9
|
Given the monster has an alignment
|
10
10
|
Then that alignment should be "Neutral"
|
@@ -0,0 +1,17 @@
|
|
1
|
+
Feature: steps with variations, such as alternative words or optional words
|
2
|
+
Scenario: alternative words
|
3
|
+
Given there is a strong monster
|
4
|
+
Then it should be strong
|
5
|
+
And it should be tough
|
6
|
+
Scenario: optional words
|
7
|
+
Given there is a strong monster
|
8
|
+
Then it should be badass
|
9
|
+
And it should be a badass
|
10
|
+
Scenario: optional parts of words
|
11
|
+
Given there is a strong monster
|
12
|
+
Then it should be terrible
|
13
|
+
And it should be terriblest
|
14
|
+
Scenario: putting it all together
|
15
|
+
Given there is a strong monster
|
16
|
+
Then it should have 2 terrifying hitpoints
|
17
|
+
And it has 2 hitpoint
|
data/lib/turnip.rb
CHANGED
@@ -1,48 +1,33 @@
|
|
1
|
-
require "gherkin"
|
2
|
-
require "gherkin/formatter/tag_count_formatter"
|
3
|
-
|
4
1
|
require "turnip/version"
|
5
2
|
require "turnip/dsl"
|
6
|
-
|
7
|
-
require
|
3
|
+
require "turnip/execute"
|
4
|
+
require "turnip/define"
|
5
|
+
require "turnip/builder"
|
6
|
+
require "turnip/step_definition"
|
7
|
+
require "turnip/placeholder"
|
8
|
+
require "turnip/table"
|
8
9
|
|
9
10
|
module Turnip
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
autoload :RunnerDSL, 'turnip/runner_dsl'
|
21
|
-
autoload :ScenarioContext, 'turnip/scenario_context'
|
11
|
+
class Pending < StandardError; end
|
12
|
+
class Ambiguous < StandardError; end
|
13
|
+
|
14
|
+
##
|
15
|
+
#
|
16
|
+
# The global step module, adding steps here will make them available in all
|
17
|
+
# your tests.
|
18
|
+
#
|
19
|
+
module Steps
|
20
|
+
end
|
22
21
|
|
23
22
|
class << self
|
24
23
|
attr_accessor :type
|
25
|
-
|
26
|
-
def run(feature_file)
|
27
|
-
Turnip::Builder.build(feature_file).features.each do |feature|
|
28
|
-
describe feature.name, feature.metadata_hash do
|
29
|
-
feature.scenarios.each do |scenario|
|
30
|
-
it scenario.name, scenario.metadata_hash do
|
31
|
-
Turnip::ScenarioRunner.new(self).load(Turnip::ScenarioContext.new(feature, scenario)).run
|
32
|
-
end
|
33
|
-
end
|
34
|
-
end
|
35
|
-
end
|
36
|
-
end
|
37
24
|
end
|
38
25
|
end
|
39
26
|
|
40
27
|
Turnip.type = :turnip
|
41
28
|
|
42
|
-
|
43
|
-
|
44
|
-
RSpec.configure do |config|
|
45
|
-
config.pattern << ",**/*.feature"
|
46
|
-
end
|
29
|
+
Module.send(:include, Turnip::Define)
|
47
30
|
|
48
31
|
self.extend Turnip::DSL
|
32
|
+
|
33
|
+
require "turnip/rspec"
|
data/lib/turnip/builder.rb
CHANGED
@@ -1,13 +1,11 @@
|
|
1
|
+
require "gherkin"
|
2
|
+
|
1
3
|
module Turnip
|
2
4
|
class Builder
|
3
5
|
module Tags
|
4
6
|
def tags
|
5
7
|
@raw.tags.map { |tag| tag.name.sub(/^@/, '') }
|
6
8
|
end
|
7
|
-
|
8
|
-
def active_tags
|
9
|
-
tags.map(&:to_sym)
|
10
|
-
end
|
11
9
|
|
12
10
|
def tags_hash
|
13
11
|
Hash[tags.map { |t| [t.to_sym, true] }]
|
@@ -36,13 +34,9 @@ module Turnip
|
|
36
34
|
@scenarios = []
|
37
35
|
@backgrounds = []
|
38
36
|
end
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
def active_tags
|
43
|
-
active_tags = [:global]
|
44
|
-
active_tags << feature_tag.to_sym if feature_tag
|
45
|
-
active_tags + super
|
37
|
+
|
38
|
+
def line
|
39
|
+
@raw.line
|
46
40
|
end
|
47
41
|
|
48
42
|
def metadata_hash
|
@@ -88,30 +82,36 @@ module Turnip
|
|
88
82
|
Scenario.new(@raw).tap do |scenario|
|
89
83
|
scenario.steps = steps.map do |step|
|
90
84
|
new_description = step.description.gsub(/<([^>]*)>/) { |_| Hash[headers.zip(row)][$1] }
|
91
|
-
Step.new(new_description, step.
|
85
|
+
Step.new(new_description, step.extra_args, step.line)
|
92
86
|
end
|
93
87
|
end
|
94
88
|
end
|
95
89
|
end
|
96
90
|
end
|
97
91
|
|
98
|
-
class Step < Struct.new(:description, :
|
92
|
+
class Step < Struct.new(:description, :extra_args, :line)
|
93
|
+
# 1.9.2 support hack
|
94
|
+
def split(*args)
|
95
|
+
self.to_s.split(*args)
|
96
|
+
end
|
97
|
+
|
98
|
+
def to_s
|
99
|
+
description
|
100
|
+
end
|
99
101
|
end
|
100
102
|
|
101
103
|
attr_reader :features
|
102
104
|
|
103
105
|
class << self
|
104
106
|
def build(feature_file)
|
105
|
-
Turnip::Builder.new
|
106
|
-
|
107
|
-
parser
|
108
|
-
parser.parse(feature_file.content, nil, 0)
|
107
|
+
Turnip::Builder.new.tap do |builder|
|
108
|
+
parser = Gherkin::Parser::Parser.new(builder, true)
|
109
|
+
parser.parse(File.read(feature_file), nil, 0)
|
109
110
|
end
|
110
111
|
end
|
111
112
|
end
|
112
113
|
|
113
|
-
def initialize
|
114
|
-
@feature_file = feature_file
|
114
|
+
def initialize
|
115
115
|
@features = []
|
116
116
|
end
|
117
117
|
|
@@ -122,8 +122,6 @@ module Turnip
|
|
122
122
|
|
123
123
|
def feature(feature)
|
124
124
|
@current_feature = Feature.new(feature)
|
125
|
-
# Automatically add a tag based on the name of the feature to the Feature if configured to
|
126
|
-
@current_feature.feature_tag = @feature_file.feature_name if Turnip::Config.autotag_features
|
127
125
|
@features << @current_feature
|
128
126
|
end
|
129
127
|
|
@@ -141,12 +139,16 @@ module Turnip
|
|
141
139
|
end
|
142
140
|
|
143
141
|
def step(step)
|
142
|
+
extra_args = []
|
144
143
|
if step.doc_string
|
145
|
-
|
144
|
+
extra_args.push step.doc_string.value
|
146
145
|
elsif step.rows
|
147
|
-
|
146
|
+
extra_args.push Turnip::Table.new(step.rows.map { |row| row.cells(&:value) })
|
148
147
|
end
|
149
|
-
@current_step_context.steps << Step.new(step.name,
|
148
|
+
@current_step_context.steps << Step.new(step.name, extra_args, step.line)
|
149
|
+
end
|
150
|
+
|
151
|
+
def uri(*)
|
150
152
|
end
|
151
153
|
|
152
154
|
def eof
|
@@ -0,0 +1,9 @@
|
|
1
|
+
module Turnip
|
2
|
+
module Define
|
3
|
+
def step(expression, &block)
|
4
|
+
step = Turnip::StepDefinition.new(expression, &block)
|
5
|
+
send(:define_method, "match: #{expression}") { |description| step.match(description) }
|
6
|
+
send(:define_method, expression, &block)
|
7
|
+
end
|
8
|
+
end
|
9
|
+
end
|
data/lib/turnip/dsl.rb
CHANGED
@@ -5,26 +5,20 @@ module Turnip
|
|
5
5
|
end
|
6
6
|
|
7
7
|
def step(description, &block)
|
8
|
-
|
8
|
+
Turnip::Steps.step(description, &block)
|
9
9
|
end
|
10
10
|
|
11
11
|
def steps_for(tag, &block)
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
end
|
23
|
-
end
|
24
|
-
entry = Turnip::StepModule::Entry.new([:global], anon, [])
|
25
|
-
Turnip::StepModule.module_registry[:global] << entry
|
26
|
-
entry
|
27
|
-
end
|
12
|
+
if tag.to_s == "global"
|
13
|
+
warn "[Turnip] using steps_for(:global) is deprecated, add steps to Turnip::Steps instead"
|
14
|
+
Turnip::Steps.module_eval(&block)
|
15
|
+
else
|
16
|
+
Module.new do
|
17
|
+
singleton_class.send(:define_method, :tag) { tag }
|
18
|
+
module_eval(&block)
|
19
|
+
::RSpec.configure { |c| c.include self, tag => true }
|
20
|
+
end
|
21
|
+
end
|
28
22
|
end
|
29
23
|
end
|
30
24
|
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
module Turnip
|
2
|
+
module Execute
|
3
|
+
def step(description, *extra_args)
|
4
|
+
extra_args.concat(description.extra_args) if description.respond_to?(:extra_args)
|
5
|
+
|
6
|
+
matches = methods.map do |method|
|
7
|
+
next unless method.to_s.start_with?("match: ")
|
8
|
+
send(method.to_s, description.to_s)
|
9
|
+
end.compact
|
10
|
+
raise Turnip::Pending, description if matches.length == 0
|
11
|
+
raise Turnip::Ambiguous, description if matches.length > 1
|
12
|
+
send(matches.first.expression, *(matches.first.params + extra_args))
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
data/lib/turnip/rspec.rb
ADDED
@@ -0,0 +1,80 @@
|
|
1
|
+
require "turnip"
|
2
|
+
require "rspec"
|
3
|
+
|
4
|
+
module Turnip
|
5
|
+
module RSpec
|
6
|
+
|
7
|
+
##
|
8
|
+
#
|
9
|
+
# This module hooks Turnip into RSpec by duck punching the load Kernel
|
10
|
+
# method. If the file is a feature file, we run Turnip instead!
|
11
|
+
#
|
12
|
+
module Loader
|
13
|
+
def load(*a, &b)
|
14
|
+
if a.first.end_with?('.feature')
|
15
|
+
begin
|
16
|
+
require 'spec_helper'
|
17
|
+
rescue LoadError
|
18
|
+
end
|
19
|
+
Turnip::RSpec.run(a.first)
|
20
|
+
else
|
21
|
+
super
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
##
|
27
|
+
#
|
28
|
+
# This module provides an improved method to run steps inside RSpec, adding
|
29
|
+
# proper support for pending steps, as well as nicer backtraces.
|
30
|
+
#
|
31
|
+
module Execute
|
32
|
+
include Turnip::Execute
|
33
|
+
|
34
|
+
def run_step(feature_file, step)
|
35
|
+
begin
|
36
|
+
step(step)
|
37
|
+
rescue Turnip::Pending
|
38
|
+
pending("No such step: '#{step}'")
|
39
|
+
rescue StandardError => e
|
40
|
+
e.backtrace.push "#{feature_file}:#{step.line}:in `#{step.description}'"
|
41
|
+
raise e
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
class << self
|
47
|
+
def run(feature_file)
|
48
|
+
Turnip::Builder.build(feature_file).features.each do |feature|
|
49
|
+
describe feature.name, feature.metadata_hash do
|
50
|
+
before do
|
51
|
+
# This is kind of a hack, but it will make RSpec throw way nicer exceptions
|
52
|
+
example.metadata[:file_path] = feature_file
|
53
|
+
|
54
|
+
feature.backgrounds.map(&:steps).flatten.each do |step|
|
55
|
+
run_step(feature_file, step)
|
56
|
+
end
|
57
|
+
end
|
58
|
+
feature.scenarios.each do |scenario|
|
59
|
+
describe scenario.name, scenario.metadata_hash do
|
60
|
+
it scenario.steps.map(&:description).join(' -> ') do
|
61
|
+
scenario.steps.each do |step|
|
62
|
+
run_step(feature_file, step)
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
::RSpec::Core::Configuration.send(:include, Turnip::RSpec::Loader)
|
75
|
+
|
76
|
+
::RSpec.configure do |config|
|
77
|
+
config.include Turnip::RSpec::Execute
|
78
|
+
config.include Turnip::Steps
|
79
|
+
config.pattern << ",**/*.feature"
|
80
|
+
end
|