turnip 0.2.0 → 0.3.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 +2 -1
- data/.travis.yml +5 -0
- data/README.md +196 -44
- data/Rakefile +8 -0
- data/examples/alignment_steps.rb +7 -0
- data/examples/autoload_steps.feature +5 -0
- data/examples/autoload_steps.rb +5 -0
- data/examples/dragon_steps.rb +17 -0
- data/examples/evil_steps.rb +7 -0
- data/examples/knight_steps.rb +29 -0
- data/examples/more_steps.rb +7 -0
- data/examples/neutral_steps.rb +7 -0
- data/examples/red_dragon_steps.rb +18 -0
- data/examples/step_calling.feature +14 -0
- data/examples/step_calling_steps.rb +23 -0
- data/examples/steps.rb +0 -22
- data/examples/steps_for_super.feature +16 -0
- data/lib/turnip.rb +12 -12
- data/lib/turnip/builder.rb +20 -4
- data/lib/turnip/config.rb +18 -0
- data/lib/turnip/dsl.rb +19 -13
- data/lib/turnip/feature_file.rb +20 -0
- data/lib/turnip/loader.rb +6 -3
- data/lib/turnip/placeholder.rb +1 -1
- data/lib/turnip/runner_dsl.rb +9 -0
- data/lib/turnip/scenario_context.rb +41 -0
- data/lib/turnip/scenario_runner.rb +35 -0
- data/lib/turnip/step_definition.rb +14 -30
- data/lib/turnip/step_loader.rb +27 -0
- data/lib/turnip/step_module.rb +89 -0
- data/lib/turnip/table.rb +12 -0
- data/lib/turnip/version.rb +1 -1
- data/spec/builder_spec.rb +41 -2
- data/spec/dsl_spec.rb +22 -34
- data/spec/feature_file_spec.rb +18 -0
- data/spec/integration_spec.rb +1 -1
- data/spec/runner_dsl_spec.rb +23 -0
- data/spec/scenario_context_spec.rb +51 -0
- data/spec/scenario_runner_spec.rb +79 -0
- data/spec/spec_helper.rb +1 -3
- data/spec/step_definition_spec.rb +22 -34
- data/spec/step_loader_spec.rb +29 -0
- data/spec/step_module_spec.rb +106 -0
- data/spec/table_spec.rb +8 -1
- data/turnip.gemspec +2 -1
- metadata +51 -7
data/.gitignore
CHANGED
data/.travis.yml
ADDED
data/README.md
CHANGED
@@ -1,5 +1,7 @@
|
|
1
1
|
# Turnip
|
2
2
|
|
3
|
+
[](http://travis-ci.org/jnicklas/turnip)
|
4
|
+
|
3
5
|
Turnip is a [Gherkin](https://github.com/cucumber/cucumber/wiki/Gherkin)
|
4
6
|
extension for RSpec. It allows you to write tests in Gherkin and run them
|
5
7
|
through your RSpec environment. Basically you can write cucumber features in
|
@@ -28,6 +30,17 @@ exist), and add the following line:
|
|
28
30
|
-r turnip
|
29
31
|
```
|
30
32
|
|
33
|
+
## Development
|
34
|
+
|
35
|
+
* Source hosted at [GitHub](http://github.com/jnicklas/turnip).
|
36
|
+
* Please direct questions, discussion or problems to the [mailing list](http://groups.google.com/group/ruby-turnip).
|
37
|
+
Please do not open an issue on GitHub if you have a question.
|
38
|
+
* If you found a reproducible bug, open a [GitHub Issue](http://github.com/jnicklas/turnip/issues) to submit a bug report.
|
39
|
+
* Please do not contact any of the maintainers directly, unless you have found a security related issue.
|
40
|
+
|
41
|
+
Pull requests are very welcome (and even better than bug reports)!
|
42
|
+
Please create a topic branch for every separate change you make.
|
43
|
+
|
31
44
|
## Compatibility
|
32
45
|
|
33
46
|
Turnip does not work on Ruby 1.8.X.
|
@@ -60,9 +73,33 @@ Yes, that's really it.
|
|
60
73
|
|
61
74
|
## Defining steps
|
62
75
|
|
63
|
-
You might want to define some steps.
|
64
|
-
|
65
|
-
|
76
|
+
You might want to define some steps. Just as in cucumber, your step files
|
77
|
+
should be named `[something]_steps.rb`. All files ending in `*steps.rb`
|
78
|
+
will be automatically required if they are under the Turnip step directory.
|
79
|
+
|
80
|
+
The default step directory for Turnip is `spec/`. You can override this
|
81
|
+
in your `spec_helper` by setting `Turnip::Config.step_dirs`. For example:
|
82
|
+
|
83
|
+
``` ruby
|
84
|
+
# spec/spec_helper.rb
|
85
|
+
RSpec.configure do |config|
|
86
|
+
Turnip::Config.step_dirs = 'examples'
|
87
|
+
Turnip::StepLoader.load_steps
|
88
|
+
end
|
89
|
+
```
|
90
|
+
|
91
|
+
This would set the Turnip step dirs to `examples/` and automatically load
|
92
|
+
all `*steps.rb` files anywhere under that directory.
|
93
|
+
|
94
|
+
The steps you define in your step files can be global or they can be scoped
|
95
|
+
to certain features (or scenarios)...
|
96
|
+
|
97
|
+
### Global steps
|
98
|
+
Global steps can be used by any feature/scenario you write since they are
|
99
|
+
unscoped. The names must be unique across all step files in the global
|
100
|
+
namespace.
|
101
|
+
|
102
|
+
Define them in your step file like this:
|
66
103
|
|
67
104
|
``` ruby
|
68
105
|
step "there is a monster" do
|
@@ -96,89 +133,204 @@ end
|
|
96
133
|
|
97
134
|
That will match both "there is X monster" or "there are X monsters".
|
98
135
|
|
99
|
-
|
136
|
+
You can also define custom step placeholders. More on that later.
|
137
|
+
|
138
|
+
### Scoped steps
|
139
|
+
Scoped steps help you to organize steps that are specific to
|
140
|
+
certain features or scenarios. They only need to be unique within
|
141
|
+
the scopes being used by the running scenario.
|
100
142
|
|
101
|
-
|
102
|
-
placeholders, and it is bothersome to have to constantly cast them to the
|
103
|
-
correct type. Turnip's placeholder solve both problems, like this:
|
143
|
+
To define scoped steps use `steps_for`:
|
104
144
|
|
105
145
|
``` ruby
|
106
|
-
|
107
|
-
|
146
|
+
steps_for :interface do
|
147
|
+
step "I do it" do
|
148
|
+
...
|
149
|
+
end
|
108
150
|
end
|
109
151
|
|
110
|
-
|
111
|
-
|
112
|
-
|
152
|
+
steps_for :database do
|
153
|
+
step "I do it" do
|
154
|
+
...
|
113
155
|
end
|
156
|
+
end
|
157
|
+
```
|
114
158
|
|
115
|
-
|
116
|
-
|
159
|
+
Even though the step is named the same, you can now use it in
|
160
|
+
your feature files like so:
|
161
|
+
|
162
|
+
``` cucumber
|
163
|
+
@interface
|
164
|
+
Scenario: do it through the interface
|
165
|
+
|
166
|
+
@database
|
167
|
+
Scenario: do it through the database
|
168
|
+
```
|
169
|
+
|
170
|
+
Note that this would still cause an error if you tagged a Scenario
|
171
|
+
with both `@interface` and `@database` at the same time.
|
172
|
+
|
173
|
+
Scoped steps are really just Ruby modules under the covers so you
|
174
|
+
can do anything you'd normally want to do including defining
|
175
|
+
helper/utility methods and variables. Check out
|
176
|
+
[features/alignment_steps.rb](https://github.com/jnicklas/turnip/blob/master/examples/alignment_steps.rb)
|
177
|
+
and
|
178
|
+
[features/evil_steps.rb](https://github.com/jnicklas/turnip/blob/master/examples/evil_steps.rb) for basic examples.
|
179
|
+
|
180
|
+
### Reusing steps
|
181
|
+
When using scoped steps in Turnip, you can tell it to also include steps
|
182
|
+
defined in another `steps_for` block. The syntax for that is `use_steps`:
|
183
|
+
|
184
|
+
``` ruby
|
185
|
+
# dragon_steps.rb
|
186
|
+
steps_for :dragon do
|
187
|
+
use_steps :knight
|
188
|
+
|
189
|
+
attr_accessor :dragon
|
190
|
+
|
191
|
+
def dragon_attack
|
192
|
+
dragon * 10
|
193
|
+
end
|
194
|
+
|
195
|
+
step "there is a dragon" do
|
196
|
+
self.dragon = 1
|
197
|
+
end
|
198
|
+
|
199
|
+
step "the dragon attacks the knight" do
|
200
|
+
knight.attacked_for(dragon_attack)
|
201
|
+
end
|
202
|
+
end
|
203
|
+
|
204
|
+
# red_dragon_steps.rb
|
205
|
+
steps_for :red_dragon do
|
206
|
+
use_steps :dragon
|
207
|
+
|
208
|
+
attr_accessor :red_dragon
|
209
|
+
|
210
|
+
def dragon_attack
|
211
|
+
attack = super
|
212
|
+
if red_dragon
|
213
|
+
attack + 15
|
214
|
+
else
|
215
|
+
attack
|
216
|
+
end
|
217
|
+
end
|
218
|
+
|
219
|
+
step "the dragon breathes fire" do
|
220
|
+
self.red_dragon = 1
|
117
221
|
end
|
118
222
|
end
|
119
223
|
```
|
120
224
|
|
121
|
-
|
225
|
+
|
226
|
+
In this example we are making full use of Ruby's modules including using super
|
227
|
+
to call the included module's version of `dragon_attack`, for example with the
|
228
|
+
following feature file:
|
122
229
|
|
123
230
|
``` cucumber
|
124
|
-
|
125
|
-
|
231
|
+
Feature: Red Dragons are deadly
|
232
|
+
|
233
|
+
@dragon
|
234
|
+
Scenario:
|
235
|
+
Given there is a dragon
|
236
|
+
And there is a knight
|
237
|
+
When the dragon attacks the knight
|
238
|
+
Then the knight is alive
|
239
|
+
|
240
|
+
@red_dragon
|
241
|
+
Scenario:
|
242
|
+
Given there is a dragon
|
243
|
+
And the dragon breathes fire
|
244
|
+
And there is a knight
|
245
|
+
When the dragon attacks the knight
|
246
|
+
Then the knight is dead
|
126
247
|
```
|
127
248
|
|
128
|
-
|
129
|
-
|
249
|
+
### Auto-included steps
|
250
|
+
By default, Turnip will automatically make available any steps defined in
|
251
|
+
a `steps_for` block with the same name as the feature file being run. For
|
252
|
+
example, given this step file:
|
130
253
|
|
131
254
|
``` ruby
|
132
|
-
|
133
|
-
|
134
|
-
|
255
|
+
# user_signup_steps.rb
|
256
|
+
steps_for :user_signup do
|
257
|
+
step "I am on the homepage" do
|
258
|
+
...
|
259
|
+
end
|
260
|
+
|
261
|
+
step "I signup with valid info" do
|
262
|
+
...
|
263
|
+
end
|
264
|
+
|
265
|
+
step "I should see a welcome message" do
|
135
266
|
end
|
136
267
|
end
|
137
268
|
```
|
138
269
|
|
139
|
-
|
140
|
-
|
270
|
+
Then the following feature file would run just fine even though we
|
271
|
+
did not explicitly tag it with `@user_signup`.
|
141
272
|
|
142
|
-
|
273
|
+
``` cucumber
|
274
|
+
# user_signup.feature
|
275
|
+
Feature: A user can signup
|
276
|
+
Scenario: with email address
|
277
|
+
Given I am on the homepage
|
278
|
+
When I signup with valid info
|
279
|
+
Then I should see a welcome message
|
280
|
+
```
|
281
|
+
|
282
|
+
Note that the `steps_for :user_signup` did not technically have to
|
283
|
+
appear in the user_signup_steps.rb file; it could have been located
|
284
|
+
in any `steps.rb` file that was autoloaded by Turnip.
|
285
|
+
|
286
|
+
This feature can be turned off using the `Turnip::Config.autotag_features`
|
287
|
+
option if desired.
|
143
288
|
|
144
|
-
|
145
|
-
|
289
|
+
## Custom step placeholders
|
290
|
+
Do you want to be more specific in what to match in your step
|
291
|
+
placeholders? Do you find it bothersome to have to constantly cast them to the
|
292
|
+
correct type? Turnip supports custom placeholders to solve both problems, like this:
|
146
293
|
|
147
294
|
``` ruby
|
148
|
-
step "
|
149
|
-
|
295
|
+
step "there are :count monsters" do |count|
|
296
|
+
count.times { Monster.new(name) }
|
150
297
|
end
|
151
298
|
|
152
|
-
|
153
|
-
|
299
|
+
placeholder :count do
|
300
|
+
match /\d+/ do |count|
|
301
|
+
count.to_i
|
302
|
+
end
|
303
|
+
|
304
|
+
match /no/ do
|
305
|
+
0
|
306
|
+
end
|
154
307
|
end
|
155
308
|
```
|
156
309
|
|
157
|
-
|
158
|
-
run:
|
310
|
+
You would now be able to use these steps like this:
|
159
311
|
|
160
312
|
``` cucumber
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
@database
|
165
|
-
Scenario: do it through the database
|
313
|
+
Given there are 4 monsters
|
314
|
+
Given there are no monsters
|
166
315
|
```
|
167
316
|
|
168
|
-
|
317
|
+
Placeholders can extract matches from the regular expressions as well. For
|
318
|
+
example:
|
169
319
|
|
170
320
|
``` ruby
|
171
|
-
|
172
|
-
|
173
|
-
|
321
|
+
placeholder :monster do
|
322
|
+
match /(blue|green|red) (furry|bald) monster/ do |color, hair|
|
323
|
+
Monster.new(color, hair)
|
174
324
|
end
|
175
325
|
end
|
176
326
|
```
|
177
327
|
|
328
|
+
These regular expressions must not use anchors, e.g. `^` or `$`. They may not
|
329
|
+
contain named capture groups, e.g. `(?<color>blue|green)`.
|
330
|
+
|
178
331
|
## Using with Capybara
|
179
332
|
|
180
|
-
Just require `turnip/capybara
|
181
|
-
adding `-r turnip/capybara` to your `.rspec` file. You can now use the
|
333
|
+
Just require `turnip/capybara` in your `spec_helper`. You can now use the
|
182
334
|
same tags you'd use in Cucumber to switch between drivers e.g.
|
183
335
|
`@javascript` or `@selenium`. Your Turnip features will also be run
|
184
336
|
with the `:type => :request` metadata, so that Capybara is included and
|
data/Rakefile
CHANGED
@@ -0,0 +1,17 @@
|
|
1
|
+
steps_for :dragon do
|
2
|
+
use_steps :knight
|
3
|
+
|
4
|
+
attr_accessor :dragon
|
5
|
+
|
6
|
+
def dragon_attack
|
7
|
+
dragon * 10
|
8
|
+
end
|
9
|
+
|
10
|
+
step "there is a dragon" do
|
11
|
+
self.dragon = 1
|
12
|
+
end
|
13
|
+
|
14
|
+
step "the dragon attacks the knight" do
|
15
|
+
knight.attacked_for(dragon_attack)
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
steps_for :knight do
|
2
|
+
attr_accessor :knight
|
3
|
+
|
4
|
+
class Knight
|
5
|
+
def initialize
|
6
|
+
@hp = 20
|
7
|
+
end
|
8
|
+
|
9
|
+
def alive?
|
10
|
+
@hp > 0
|
11
|
+
end
|
12
|
+
|
13
|
+
def attacked_for(amount)
|
14
|
+
@hp -= amount
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
step "there is a knight" do
|
19
|
+
self.knight = Knight.new
|
20
|
+
end
|
21
|
+
|
22
|
+
step "the knight is alive" do
|
23
|
+
knight.should be_alive
|
24
|
+
end
|
25
|
+
|
26
|
+
step "the knight is dead" do
|
27
|
+
knight.should_not be_alive
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
steps_for :red_dragon do
|
2
|
+
use_steps :dragon
|
3
|
+
|
4
|
+
attr_accessor :red_dragon
|
5
|
+
|
6
|
+
def dragon_attack
|
7
|
+
attack = super
|
8
|
+
if red_dragon
|
9
|
+
attack + 15
|
10
|
+
else
|
11
|
+
attack
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
step "the dragon breathes fire" do
|
16
|
+
self.red_dragon = 1
|
17
|
+
end
|
18
|
+
end
|