rutabaga 1.0.0 → 2.0.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.travis.yml +2 -2
- data/CHANGELOG.md +33 -1
- data/Gemfile +6 -0
- data/README.md +30 -30
- data/examples/compatibility/compatibility_spec.rb +30 -0
- data/examples/test.feature +10 -0
- data/examples/test_feature_example_group.feature +15 -0
- data/examples/test_feature_example_group_spec.rb +109 -0
- data/examples/test_spec.rb +0 -67
- data/lib/rutabaga.rb +3 -0
- data/lib/rutabaga/example_group/feature.rb +45 -0
- data/lib/rutabaga/feature.rb +11 -27
- data/lib/rutabaga/util.rb +68 -0
- data/lib/rutabaga/version.rb +1 -1
- data/rutabaga-vs-turnip.jpg +0 -0
- data/rutabaga.gemspec +7 -2
- data/spec/feature_spec.rb +64 -24
- data/spec/rutabaga/util_spec.rb +130 -0
- metadata +69 -5
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 23d4ee4fca4ba9cc50f66acd809b29a67241567e
|
4
|
+
data.tar.gz: f35a01a98cc5df69b2207bb5d35d35f75ab1fb71
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: a0f89ac99d40a51f25b51d35a7a4313aa24804fc7e0a6fadb5160370392e134039220e56c9385373497f1cc9f120304f8e756b7ccf4a2c0b82087995ddb7ba58
|
7
|
+
data.tar.gz: 3fc0d2e7d30939fd5e44a2890ffa431f98f05e9481bfe11ded7bae5e9030247f480b48872ce6bfc5724a6f7196b19fd30d095fe93d734b68193e7627bd7b6bab
|
data/.travis.yml
CHANGED
data/CHANGELOG.md
CHANGED
@@ -1,6 +1,38 @@
|
|
1
1
|
# Changes
|
2
2
|
|
3
|
+
## Version 2.0.0
|
4
|
+
|
5
|
+
- Features should now be called directly in the describe block rather than inside an `it` block. This allows specific scenarios to be run without having to run the entire feature.
|
6
|
+
|
7
|
+
Old:
|
8
|
+
|
9
|
+
```ruby
|
10
|
+
describe "the feature" do
|
11
|
+
it "runs the feature" do
|
12
|
+
feature
|
13
|
+
end
|
14
|
+
|
15
|
+
step "first step" do
|
16
|
+
...
|
17
|
+
end
|
18
|
+
end
|
19
|
+
```
|
20
|
+
|
21
|
+
New:
|
22
|
+
|
23
|
+
```ruby
|
24
|
+
feature "the feature" do
|
25
|
+
step "first step" do
|
26
|
+
...
|
27
|
+
end
|
28
|
+
end
|
29
|
+
```
|
30
|
+
|
31
|
+
The old way is deprecated.
|
32
|
+
- Refactor of Turnip and RSpec integration to simplify
|
33
|
+
- Improved feature finding, allowing features in the current directory to be found without specifying full path
|
34
|
+
|
3
35
|
## Version 1.0.0
|
4
36
|
|
5
37
|
- Drop support for turnip versions less than 2.
|
6
|
-
- Drop support (because of turnip) for rspec versions less than 3.
|
38
|
+
- Drop support (because of turnip) for rspec versions less than 3.
|
data/Gemfile
CHANGED
data/README.md
CHANGED
@@ -1,5 +1,7 @@
|
|
1
1
|
# Rutabaga
|
2
2
|
|
3
|
+
![image](rutabaga-vs-turnip.jpg)
|
4
|
+
|
3
5
|
[Turnip](https://github.com/jnicklas/turnip) hacks to enable running turnips from inside spec files, rather than outside.
|
4
6
|
|
5
7
|
Rutabaga allows you to invert the control of feature files, so that features are called from your `_spec.rb` files rather than the other way around. Step definitions are then put into the `_spec.rb` files as well. The steps are then scoped to that particular test.
|
@@ -7,6 +9,7 @@ Rutabaga allows you to invert the control of feature files, so that features are
|
|
7
9
|
This means that it is simple to create tests that are described by a class (such as controller tests in rspec-rails).
|
8
10
|
|
9
11
|
[![Build Status](https://travis-ci.org/simplybusiness/rutabaga.svg?branch=master)](https://travis-ci.org/simplybusiness/rutabaga)
|
12
|
+
[![Gem Version](https://badge.fury.io/rb/rutabaga.svg)](https://badge.fury.io/rb/rutabaga)
|
10
13
|
|
11
14
|
## Installation
|
12
15
|
|
@@ -53,19 +56,17 @@ end
|
|
53
56
|
|
54
57
|
### Running a feature file from a spec file
|
55
58
|
|
56
|
-
|
57
|
-
|
58
|
-
For file `spec/controllers/test_feature_spec.rb`
|
59
|
+
If you create a file `spec/controllers/test_feature_spec.rb` and add:
|
59
60
|
|
60
61
|
```ruby
|
61
|
-
|
62
|
-
|
62
|
+
feature "should run feature" do
|
63
|
+
|
63
64
|
end
|
64
65
|
```
|
65
66
|
|
66
|
-
|
67
|
+
Rutabaga will run `spec/controllers/test_feature.feature`.
|
67
68
|
|
68
|
-
Features are found either with the same name as the spec file, or as specified
|
69
|
+
Features are found either with the same name as the spec file, or as specified by the feature `feature "relative_from_root/path/to/feature/file.feature"`. So, if you have:
|
69
70
|
|
70
71
|
`spec/controllers/feature_test_spec.rb`
|
71
72
|
|
@@ -73,45 +74,41 @@ Then the feature will be:
|
|
73
74
|
|
74
75
|
`spec/controllers/feature_test.feature`
|
75
76
|
|
76
|
-
Alternatively, if the feature is specified in the `
|
77
|
+
Alternatively, if the feature is specified in the `feature`, that takes precedence:
|
77
78
|
|
78
79
|
```ruby
|
79
|
-
|
80
|
-
|
80
|
+
feature "spec/features/test.feature" do
|
81
|
+
|
81
82
|
end
|
82
83
|
```
|
83
84
|
|
84
|
-
|
85
|
-
|
86
|
-
Second alternative, is specifying the feature file in the `feature` command:
|
85
|
+
Path can also be relative to the spec location so:
|
87
86
|
|
88
87
|
```ruby
|
89
|
-
|
90
|
-
|
88
|
+
feature "test.feature" do
|
89
|
+
|
91
90
|
end
|
92
91
|
```
|
93
92
|
|
94
|
-
Will run `spec/
|
93
|
+
Will run `spec/controllers/test.feature`.
|
94
|
+
|
95
|
+
**Note** Anywhere that a `.feature` extension can be used, a `.rutabaga` extension is also valid.
|
95
96
|
|
96
97
|
### Definining steps
|
97
98
|
|
98
99
|
Steps are defined in the same way as in Turnip, however, steps can be defined within the rspec context and are scoped to only be available there.
|
99
100
|
|
100
101
|
```ruby
|
101
|
-
|
102
|
-
it "should run feature" do
|
103
|
-
feature
|
104
|
-
end
|
102
|
+
feature "step will only be in this context" do
|
105
103
|
|
106
104
|
step "action :named" do |named| do
|
107
105
|
expect(named).to eq("a name")
|
108
106
|
end
|
109
107
|
end
|
110
108
|
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
end
|
109
|
+
feature "step 'action :named' is not available here" do
|
110
|
+
|
111
|
+
# missing step will cause tests to be marked as pending"
|
115
112
|
end
|
116
113
|
```
|
117
114
|
|
@@ -127,15 +124,18 @@ Other than these differences, Rutabaga is a tiny shim over Turnip and all featur
|
|
127
124
|
* Test those rules whereever/however appropriate (not just through Capybara/black box)
|
128
125
|
* Use the full power of RSpec (so being able to describe a class and then test it)
|
129
126
|
|
130
|
-
From my point of view, the fundamental purpose of Turnip/Cucumber is to document the system in end-user readable form. It is not just to do integration tests.
|
131
|
-
|
132
127
|
The most important functionality in a system is the business rules. These range from what appears on a page, to complex rules around when emails should be sent to who. For example, we've written Gherkin tests to test premium changes when a customer changes their insurance coverage.
|
133
128
|
|
134
129
|
These rules are often implemented in a Model, a lib class, or some other specific class in the system, especially if the application is well modularized.
|
135
130
|
|
136
|
-
In any case, business rules are usually implemented somewhere inside a class tested by a unit test.
|
131
|
+
In any case, business rules are usually implemented somewhere inside a class tested by a unit test. Those business rules should be tested in Cucumber/Turnip without having to go through the whole system, and without having to have duplicate tests, one inside rspec and another inside features.
|
132
|
+
|
133
|
+
The goal is to test just the business rule, in Rutabaga, and not the login, the html, the steps to get there, etc. That way, when the rule changes, only the feature, the test code and the class in question need to change. The test is not affected by wider ranging changes, and is therefore less brittle. The features run at the unit code level, but are acceptance tests.
|
134
|
+
|
135
|
+
## Notes/Issues
|
137
136
|
|
138
|
-
|
137
|
+
1. Capybara's rspec extension also redefines feature, so rutabaga will block capaybara's feature example groups
|
138
|
+
from working.
|
139
139
|
|
140
140
|
## Contributing
|
141
141
|
|
@@ -157,9 +157,9 @@ Put the following (example in a `Gemfile_for_xxx`) to test other versions of gem
|
|
157
157
|
# Use global Gemfile and customize
|
158
158
|
eval(IO.read('Gemfile'), binding)
|
159
159
|
|
160
|
-
gem 'turnip', '1.
|
160
|
+
gem 'turnip', '1.3.1'
|
161
161
|
```
|
162
162
|
|
163
163
|
## Copyright
|
164
164
|
|
165
|
-
Copyright © 2012-
|
165
|
+
Copyright © 2012-2016 Simply Business. See LICENSE for details.
|
@@ -0,0 +1,30 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'capybara/rspec'
|
3
|
+
|
4
|
+
describe "capaybara rails does not overwrite the feature command" do
|
5
|
+
feature '../test2.feature' do
|
6
|
+
step "that :first + :second is calculated" do |first, second|
|
7
|
+
@first = first
|
8
|
+
@second = second
|
9
|
+
end
|
10
|
+
|
11
|
+
step "my result is :result" do |result|
|
12
|
+
expect(@first.to_i + @second.to_i - 1).to eq(result.to_i)
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
describe "turnip doesn't overwrite the type", type: :parent_group do
|
18
|
+
feature '../test2.feature' do
|
19
|
+
step "that :first + :second is calculated" do |first, second|
|
20
|
+
metadata_type = RSpec.current_example.example_group.metadata[:type]
|
21
|
+
|
22
|
+
puts "feature metadata type is preserved as #{metadata_type}"
|
23
|
+
|
24
|
+
expect(metadata_type).to eq(:parent_group)
|
25
|
+
end
|
26
|
+
|
27
|
+
step "my result is :result" do |result|
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
data/examples/test.feature
CHANGED
@@ -3,3 +3,13 @@ Feature: Test that rspec will call the feature
|
|
3
3
|
Scenario: ensures the feature is called
|
4
4
|
Given that 2 + 2 is calculated
|
5
5
|
Then my result is 4
|
6
|
+
|
7
|
+
Scenario Outline: ensures the outline feature is called
|
8
|
+
Given that <a> + <b> is calculated
|
9
|
+
Then my result is <c>
|
10
|
+
|
11
|
+
Examples:
|
12
|
+
| a | b | c |
|
13
|
+
| 1 | 1 | 2 |
|
14
|
+
| 2 | 2 | 4 |
|
15
|
+
| 3 | 3 | 5 |
|
@@ -0,0 +1,15 @@
|
|
1
|
+
Feature: Test that rspec will call the feature
|
2
|
+
|
3
|
+
Scenario: ensures the feature is called
|
4
|
+
Given that 2 + 2 is calculated
|
5
|
+
Then my result is 4
|
6
|
+
|
7
|
+
Scenario Outline: ensures the outline feature is called with one failing example which can be called individually
|
8
|
+
Given that <a> + <b> is calculated
|
9
|
+
Then my result is <c>
|
10
|
+
|
11
|
+
Examples:
|
12
|
+
| a | b | c |
|
13
|
+
| 1 | 1 | 2 |
|
14
|
+
| 2 | 2 | 4 |
|
15
|
+
| 3 | 3 | 5 |
|
@@ -0,0 +1,109 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe "test feature argument" do
|
4
|
+
feature
|
5
|
+
|
6
|
+
step "that :first + :second is calculated" do |first, second|
|
7
|
+
@first = first
|
8
|
+
@second = second
|
9
|
+
end
|
10
|
+
|
11
|
+
step "my result is :result" do |result|
|
12
|
+
expect(@first.to_i + @second.to_i).to eq(result.to_i)
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
feature "feature block" do
|
17
|
+
step "that :first + :second is calculated" do |first, second|
|
18
|
+
@first = first
|
19
|
+
@second = second
|
20
|
+
end
|
21
|
+
|
22
|
+
step "my result is :result" do |result|
|
23
|
+
expect(@first.to_i + @second.to_i).to eq(result.to_i)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
describe "feature block inside a describe block" do
|
28
|
+
feature do
|
29
|
+
|
30
|
+
step "that :first + :second is calculated" do |first, second|
|
31
|
+
@first = first
|
32
|
+
@second = second
|
33
|
+
end
|
34
|
+
|
35
|
+
step "my result is :result" do |result|
|
36
|
+
expect(@first.to_i + @second.to_i).to eq(result.to_i)
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
describe "should find the feature file using the root (and monkey patching the result)" do
|
42
|
+
feature "examples/test2.feature"
|
43
|
+
|
44
|
+
step "that :first + :second is calculated" do |first, second|
|
45
|
+
@first = first
|
46
|
+
@second = second
|
47
|
+
end
|
48
|
+
|
49
|
+
step "my result is :result" do |result|
|
50
|
+
expect(@first.to_i + @second.to_i - 1).to eq(result.to_i)
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
describe "causes a failing test" do
|
55
|
+
feature "examples/test2.feature"
|
56
|
+
|
57
|
+
step "that :first + :second is calculated" do |first, second|
|
58
|
+
@first = first
|
59
|
+
@second = second
|
60
|
+
end
|
61
|
+
|
62
|
+
step "my result is :result" do |result|
|
63
|
+
expect(@first.to_i + @second.to_i).to eq(result.to_i)
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
describe "finds a feature file given as parameter to the 'feature' method" do
|
68
|
+
feature "examples/test3.feature"
|
69
|
+
|
70
|
+
step "that :first * :second is calculated" do |first, second|
|
71
|
+
@first = first
|
72
|
+
@second = second
|
73
|
+
end
|
74
|
+
|
75
|
+
step "my result is :result" do |result|
|
76
|
+
expect(@first.to_i * @second.to_i).to eq(result.to_i)
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
describe "finds a feature file with a different name in the same directory" do
|
81
|
+
feature "test3.feature"
|
82
|
+
|
83
|
+
step "that :first * :second is calculated" do |first, second|
|
84
|
+
@first = first
|
85
|
+
@second = second
|
86
|
+
end
|
87
|
+
|
88
|
+
step "my result is :result" do |result|
|
89
|
+
expect(@first.to_i * @second.to_i).to eq(result.to_i)
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
describe "backgrounds are properly called" do
|
94
|
+
feature "examples/test_background.feature"
|
95
|
+
|
96
|
+
step "we add :initial" do |initial|
|
97
|
+
@initial = 10
|
98
|
+
end
|
99
|
+
|
100
|
+
step "that :first * :second is calculated" do |first, second|
|
101
|
+
@first = first
|
102
|
+
@second = second
|
103
|
+
end
|
104
|
+
|
105
|
+
step "my result is :result" do |result|
|
106
|
+
expect(@initial.to_i + @first.to_i * @second.to_i).to eq(result.to_i)
|
107
|
+
end
|
108
|
+
|
109
|
+
end
|
data/examples/test_spec.rb
CHANGED
@@ -1,20 +1,5 @@
|
|
1
1
|
require 'spec_helper'
|
2
2
|
|
3
|
-
describe "test" do
|
4
|
-
it "should run feature" do
|
5
|
-
feature
|
6
|
-
end
|
7
|
-
|
8
|
-
step "that :first + :second is calculated" do |first, second|
|
9
|
-
@first = first
|
10
|
-
@second = second
|
11
|
-
end
|
12
|
-
|
13
|
-
step "my result is :result" do |result|
|
14
|
-
expect(@first.to_i + @second.to_i).to eq(result.to_i)
|
15
|
-
end
|
16
|
-
end
|
17
|
-
|
18
3
|
describe "should find the feature file using the root (and monkey patching the result)" do
|
19
4
|
it "examples/test2.feature" do
|
20
5
|
feature
|
@@ -30,55 +15,3 @@ describe "should find the feature file using the root (and monkey patching the r
|
|
30
15
|
end
|
31
16
|
|
32
17
|
end
|
33
|
-
|
34
|
-
describe "causes a failing test" do
|
35
|
-
it "examples/test2.feature" do
|
36
|
-
feature
|
37
|
-
end
|
38
|
-
|
39
|
-
step "that :first + :second is calculated" do |first, second|
|
40
|
-
@first = first
|
41
|
-
@second = second
|
42
|
-
end
|
43
|
-
|
44
|
-
step "my result is :result" do |result|
|
45
|
-
expect(@first.to_i + @second.to_i).to eq(result.to_i)
|
46
|
-
end
|
47
|
-
|
48
|
-
end
|
49
|
-
|
50
|
-
describe "finds a feature file given as parameter to the 'feature' method" do
|
51
|
-
it "implements the named feature" do
|
52
|
-
feature "examples/test3.feature"
|
53
|
-
end
|
54
|
-
|
55
|
-
step "that :first * :second is calculated" do |first, second|
|
56
|
-
@first = first
|
57
|
-
@second = second
|
58
|
-
end
|
59
|
-
|
60
|
-
step "my result is :result" do |result|
|
61
|
-
expect(@first.to_i * @second.to_i).to eq(result.to_i)
|
62
|
-
end
|
63
|
-
|
64
|
-
end
|
65
|
-
|
66
|
-
describe "backgrounds are properly called" do
|
67
|
-
it "implements the named feature" do
|
68
|
-
feature "examples/test_background.feature"
|
69
|
-
end
|
70
|
-
|
71
|
-
step "we add :initial" do |initial|
|
72
|
-
@initial = 10
|
73
|
-
end
|
74
|
-
|
75
|
-
step "that :first * :second is calculated" do |first, second|
|
76
|
-
@first = first
|
77
|
-
@second = second
|
78
|
-
end
|
79
|
-
|
80
|
-
step "my result is :result" do |result|
|
81
|
-
expect(@initial.to_i + @first.to_i * @second.to_i).to eq(result.to_i)
|
82
|
-
end
|
83
|
-
|
84
|
-
end
|
data/lib/rutabaga.rb
CHANGED
@@ -0,0 +1,45 @@
|
|
1
|
+
require 'turnip/rspec'
|
2
|
+
require 'rspec'
|
3
|
+
|
4
|
+
# Monkey patch rspec to block capybara from using feature
|
5
|
+
class RSpec::Core::Configuration
|
6
|
+
alias_method :orig_alias_example_group_to, :alias_example_group_to
|
7
|
+
|
8
|
+
def alias_example_group_to(new_name, *args)
|
9
|
+
return if [:feature, :xfeature, :ffeature].include?(new_name)
|
10
|
+
orig_alias_example_group_to(new_name, *args)
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
# Monkey patch RSpec to add the feature method in example groups
|
15
|
+
class RSpec::Core::ExampleGroup
|
16
|
+
class << self
|
17
|
+
alias_method :orig_subclass, :subclass
|
18
|
+
|
19
|
+
def subclass(parent, description, args, &example_group_block)
|
20
|
+
self.orig_subclass(parent, description, args, &example_group_block).tap do |describe|
|
21
|
+
|
22
|
+
if args.any? { |arg| arg.kind_of?(Hash) && arg[:rutabaga] }
|
23
|
+
Rutabaga::ExampleGroup::Feature.feature(describe, description, args)
|
24
|
+
end
|
25
|
+
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
define_example_group_method :feature, :rutabaga => true
|
31
|
+
end
|
32
|
+
|
33
|
+
module Rutabaga
|
34
|
+
module ExampleGroup
|
35
|
+
module Feature
|
36
|
+
class << self
|
37
|
+
def feature(example_group_class, description, args)
|
38
|
+
Util.require_if_exists 'turnip_helper'
|
39
|
+
|
40
|
+
Turnip::RSpec.rutabaga_run(Util.find_feature(description), example_group_class)
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
data/lib/rutabaga/feature.rb
CHANGED
@@ -3,8 +3,15 @@ require 'rspec'
|
|
3
3
|
|
4
4
|
module Rutabaga
|
5
5
|
module Feature
|
6
|
-
def feature(feature_file =
|
7
|
-
|
6
|
+
def feature(feature_file = nil)
|
7
|
+
RSpec.deprecate(
|
8
|
+
"Calling `feature` from an `it` block",
|
9
|
+
:message => "Calling `feature` from an `it` block " \
|
10
|
+
"is deprecated.\nIt should now be called directly in the " \
|
11
|
+
"`describe` block."
|
12
|
+
)
|
13
|
+
|
14
|
+
feature_file = Util.find_feature(feature_file || RSpec.current_example.description)
|
8
15
|
example_group_class = self.class
|
9
16
|
|
10
17
|
# Hack turnip into the rspec only when needed
|
@@ -14,20 +21,7 @@ module Rutabaga
|
|
14
21
|
run(feature_file, example_group_class)
|
15
22
|
end
|
16
23
|
|
17
|
-
|
18
|
-
return get_example.description if File.exists?(get_example.description)
|
19
|
-
|
20
|
-
feature_file = caller(0).find do |call|
|
21
|
-
call =~ /_spec.rb:/
|
22
|
-
end.gsub(/_spec.rb:.*\Z/, '.feature')
|
23
|
-
return feature_file if File.exists?(feature_file)
|
24
|
-
|
25
|
-
raise "Feature file not found. Tried: #{get_example.description} and #{feature_file}"
|
26
|
-
end
|
27
|
-
|
28
|
-
private
|
29
|
-
|
30
|
-
# Adapted from jnicklas/turnip v1.3.1
|
24
|
+
# Adapted from jnicklas/turnip v2.0.0
|
31
25
|
def run(feature_file, example_group_class)
|
32
26
|
Turnip::Builder.build(feature_file).features.each do |feature|
|
33
27
|
describe = example_group_class.describe feature.name, feature.metadata_hash
|
@@ -38,7 +32,7 @@ module Rutabaga
|
|
38
32
|
def run_feature(describe, feature, filename, example_group_class)
|
39
33
|
example_group_class.before do
|
40
34
|
# This is kind of a hack, but it will make RSpec throw way nicer exceptions
|
41
|
-
|
35
|
+
RSpec.current_example.metadata[:file_path] = filename
|
42
36
|
|
43
37
|
feature.backgrounds.map(&:steps).flatten.each do |step|
|
44
38
|
run_step(filename, step)
|
@@ -55,15 +49,5 @@ module Rutabaga
|
|
55
49
|
end
|
56
50
|
end
|
57
51
|
end
|
58
|
-
|
59
|
-
def get_example
|
60
|
-
@example ||= RSpec.current_example
|
61
|
-
end
|
62
52
|
end
|
63
53
|
end
|
64
|
-
|
65
|
-
::RSpec.configure do |c|
|
66
|
-
c.include Rutabaga::Feature
|
67
|
-
# Blow away turnip's pattern, and focus just on features directory
|
68
|
-
c.pattern.gsub!(",**/*.feature", ",features/**/*.feature")
|
69
|
-
end
|
@@ -0,0 +1,68 @@
|
|
1
|
+
# Utils and monkey patches for both versions of feature
|
2
|
+
|
3
|
+
# Monkey patch for Turnip to not have to copy loads of code
|
4
|
+
module Turnip::RSpec
|
5
|
+
def self.rutabaga_run(feature_file, example_group_class)
|
6
|
+
Turnip::Builder.build(feature_file).features.each do |feature|
|
7
|
+
instance_eval <<-EOS, feature_file, feature.line
|
8
|
+
describe = example_group_class.describe feature.name, feature.metadata_hash.reject { |key, _| key == :type }
|
9
|
+
run_feature(describe, feature, feature_file)
|
10
|
+
EOS
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
module Rutabaga
|
16
|
+
class Util
|
17
|
+
class << self
|
18
|
+
def find_feature(description)
|
19
|
+
tried = []
|
20
|
+
|
21
|
+
if description =~ /.*\.(feature|rutabaga)\Z/
|
22
|
+
return description if File.exists?(description)
|
23
|
+
tried << description
|
24
|
+
|
25
|
+
candidate = File.join(extract_directory, description)
|
26
|
+
return candidate if File.exists?(candidate)
|
27
|
+
tried << candidate
|
28
|
+
else
|
29
|
+
feature_files = extract_features
|
30
|
+
feature_files.each do |feature_file|
|
31
|
+
return feature_file if File.exists?(feature_file)
|
32
|
+
end
|
33
|
+
tried += feature_files
|
34
|
+
end
|
35
|
+
|
36
|
+
raise "Feature file not found. Tried: #{tried.join(', ')}"
|
37
|
+
end
|
38
|
+
|
39
|
+
def require_if_exists(filename)
|
40
|
+
require filename
|
41
|
+
rescue LoadError => e
|
42
|
+
# Don't hide LoadErrors raised in the spec helper.
|
43
|
+
raise unless e.message.include?(filename)
|
44
|
+
end
|
45
|
+
|
46
|
+
private
|
47
|
+
|
48
|
+
def extract_directory
|
49
|
+
caller(0).find do |call|
|
50
|
+
call =~ /_spec.rb:/
|
51
|
+
end.gsub(/\/[^\/]+_spec.rb:.*\Z/, '')
|
52
|
+
end
|
53
|
+
|
54
|
+
def extract_features
|
55
|
+
base = caller(0).find do |call|
|
56
|
+
call =~ /_spec.rb:/
|
57
|
+
end.gsub(/_spec.rb:.*\Z/, '')
|
58
|
+
[base+'.feature', base+'.rutabaga']
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
::RSpec.configure do |c|
|
65
|
+
c.include Rutabaga::Feature
|
66
|
+
# Blow away turnip's pattern, and focus just on features directory
|
67
|
+
c.pattern.gsub!(",**/*.feature", ",features/**/*.feature")
|
68
|
+
end
|
data/lib/rutabaga/version.rb
CHANGED
Binary file
|
data/rutabaga.gemspec
CHANGED
@@ -16,6 +16,11 @@ Gem::Specification.new do |gem|
|
|
16
16
|
gem.version = Rutabaga::VERSION
|
17
17
|
gem.license = 'MIT'
|
18
18
|
|
19
|
-
gem.add_runtime_dependency 'turnip', ['
|
20
|
-
gem.
|
19
|
+
gem.add_runtime_dependency 'turnip', ['~> 2.0.0']
|
20
|
+
gem.add_runtime_dependency 'gherkin', ['~> 2.0']
|
21
|
+
gem.add_runtime_dependency 'activesupport'
|
22
|
+
# There is a bug in 3.4.1 with turnip 2.0.x
|
23
|
+
gem.add_runtime_dependency 'rspec-mocks', ['<= 3.4.0']
|
24
|
+
gem.add_development_dependency 'capybara'
|
25
|
+
gem.add_development_dependency 'pry', '~> 0'
|
21
26
|
end
|
data/spec/feature_spec.rb
CHANGED
@@ -1,36 +1,76 @@
|
|
1
1
|
require 'spec_helper'
|
2
2
|
|
3
3
|
describe 'integration', :type => :integration do
|
4
|
-
|
5
|
-
|
6
|
-
|
4
|
+
describe 'functionality' do
|
5
|
+
before(:all) do
|
6
|
+
@result = %x(rspec -r rutabaga -fd examples/*_spec.rb 2>&1)
|
7
|
+
end
|
7
8
|
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
9
|
+
it "shows the correct description" do
|
10
|
+
expect(@result).to include('ensures the feature is called')
|
11
|
+
expect(@result).to include('that 2 + 2 is calculated')
|
12
|
+
expect(@result).to include('my result is 4')
|
13
|
+
end
|
13
14
|
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
end
|
15
|
+
it "executes features as an argument" do
|
16
|
+
expect(@result).to include('test feature argument')
|
17
|
+
end
|
18
18
|
|
19
|
-
|
20
|
-
|
21
|
-
|
19
|
+
it "executes features as blocks/example groups" do
|
20
|
+
expect(@result).to include('feature block')
|
21
|
+
end
|
22
22
|
|
23
|
-
|
24
|
-
|
25
|
-
|
23
|
+
it "executes features as blocks inside example groups" do
|
24
|
+
expect(@result).to include('feature block inside a describe block')
|
25
|
+
end
|
26
26
|
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
27
|
+
it "should not show any pending steps" do
|
28
|
+
expect(@result).not_to include('PENDING')
|
29
|
+
expect(@result).not_to include('No such step')
|
30
|
+
end
|
31
|
+
|
32
|
+
it "prints out failures and successes" do
|
33
|
+
expect(@result).to include('19 examples, 4 failures')
|
34
|
+
end
|
35
|
+
|
36
|
+
it "should find features relative to the root" do
|
37
|
+
expect(@result).not_to include('Feature file not found')
|
38
|
+
end
|
31
39
|
|
32
|
-
|
33
|
-
|
40
|
+
it "finds the .feature file given as parameter to the 'feature' method" do
|
41
|
+
expect(@result).to include('that 2 * 4 is calculated')
|
42
|
+
expect(@result).to include('my result is 8')
|
43
|
+
end
|
44
|
+
|
45
|
+
it "should scope steps to describe blocks" do
|
46
|
+
expect(@result).not_to include('Turnip::Ambiguous')
|
47
|
+
end
|
48
|
+
|
49
|
+
it "should provide failure messages that allow a specific scenario to be run" do
|
50
|
+
expect(@result).to include("rspec ./examples/test_feature_example_group_spec.rb[1:1:1:4:1]")
|
51
|
+
end
|
52
|
+
|
53
|
+
it "should have a feature deprecation warning" do
|
54
|
+
expect(@result).to include("Calling `feature` from an `it` block is deprecated.")
|
55
|
+
end
|
34
56
|
end
|
35
57
|
|
58
|
+
describe 'compatibility' do
|
59
|
+
before(:all) do
|
60
|
+
@result = %x(rspec -r rutabaga -fd examples/compatibility/*_spec.rb 2>&1)
|
61
|
+
end
|
62
|
+
|
63
|
+
it "passes all tests" do
|
64
|
+
expect(@result).to include('2 examples, 0 failures')
|
65
|
+
end
|
66
|
+
|
67
|
+
it "runs feature blocks even if capybara/rspec is installed" do
|
68
|
+
expect(@result).to include("capaybara rails does not overwrite the feature command")
|
69
|
+
end
|
70
|
+
|
71
|
+
it "preserves the type from the surrounding describe blocks (for example rspec rails example groups)" do
|
72
|
+
expect(@result).to include("feature metadata type is preserved as parent_group")
|
73
|
+
end
|
74
|
+
|
75
|
+
end
|
36
76
|
end
|
@@ -0,0 +1,130 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'rutabaga'
|
3
|
+
|
4
|
+
describe Rutabaga::Util do
|
5
|
+
describe "location of test from stack track" do
|
6
|
+
it "finds the directory" do
|
7
|
+
expect(subject.class.send(:extract_directory)).to match(/\/rutabaga\/spec\/rutabaga\Z/)
|
8
|
+
end
|
9
|
+
|
10
|
+
it "finds the feature" do
|
11
|
+
features = subject.class.send(:extract_features)
|
12
|
+
expect(features[0]).to match(/\/rutabaga\/spec\/rutabaga\/util\.feature\Z/)
|
13
|
+
expect(features[1]).to match(/\/rutabaga\/spec\/rutabaga\/util\.rutabaga\Z/)
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
describe ".find_feature" do
|
18
|
+
let(:subject) { Rutabaga::Util.find_feature(@description) }
|
19
|
+
before do
|
20
|
+
allow(File).to receive(:exists?).with('spec/rutabaga/existing.feature').and_return(true)
|
21
|
+
allow(File).to receive(:exists?).with('spec/rutabaga/missing.feature').and_return(false)
|
22
|
+
allow(File).to receive(:exists?).with(nil).and_return(false)
|
23
|
+
end
|
24
|
+
|
25
|
+
it "returns the file if it exists" do
|
26
|
+
@description = 'spec/rutabaga/existing.feature'
|
27
|
+
expect(subject).to eq('spec/rutabaga/existing.feature')
|
28
|
+
end
|
29
|
+
|
30
|
+
describe "looks for the feature in the spec's directory" do
|
31
|
+
before do
|
32
|
+
allow(File).to receive(:exists?).with('different.feature').and_return(false)
|
33
|
+
end
|
34
|
+
|
35
|
+
it "looks directly in the directory" do
|
36
|
+
@description = 'different.feature'
|
37
|
+
expect(File).to receive(:exists?).with(/spec\/rutabaga\/different\.feature\Z/).and_return(true)
|
38
|
+
|
39
|
+
expect(subject).to match(/spec\/rutabaga\/different\.feature\Z/)
|
40
|
+
end
|
41
|
+
|
42
|
+
it "allows sub-directories" do
|
43
|
+
allow(File).to receive(:exists?).with('subdirectory/different.feature').and_return(false)
|
44
|
+
|
45
|
+
@description = 'subdirectory/different.feature'
|
46
|
+
expect(File).to receive(:exists?).with(/spec\/rutabaga\/subdirectory\/different\.feature\Z/).and_return(true)
|
47
|
+
|
48
|
+
expect(subject).to match(/spec\/rutabaga\/subdirectory\/different\.feature\Z/)
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
describe "figures out the feature name from the spec name" do
|
53
|
+
it "description is nil" do
|
54
|
+
@description = nil
|
55
|
+
allow(File).to receive(:exists?).with(/spec\/rutabaga\/util\.feature\Z/).and_return(true)
|
56
|
+
expect(subject).to match(/spec\/rutabaga\/util\.feature\Z/)
|
57
|
+
end
|
58
|
+
|
59
|
+
it "description does not match a feature file" do
|
60
|
+
@description = 'this is not a feature file'
|
61
|
+
allow(File).to receive(:exists?).with(/this is not a feature file/).and_return(false)
|
62
|
+
|
63
|
+
allow(File).to receive(:exists?).with(/spec\/rutabaga\/util\.feature\Z/).and_return(true)
|
64
|
+
expect(subject).to match(/spec\/rutabaga\/util\.feature\Z/)
|
65
|
+
end
|
66
|
+
|
67
|
+
it "description does not match a feature file" do
|
68
|
+
@description = 'this is not a feature file'
|
69
|
+
allow(File).to receive(:exists?).with(/this is not a feature file/).and_return(false)
|
70
|
+
|
71
|
+
allow(File).to receive(:exists?).with(/spec\/rutabaga\/util\.feature\Z/).and_return(false)
|
72
|
+
allow(File).to receive(:exists?).with(/spec\/rutabaga\/util\.rutabaga\Z/).and_return(true)
|
73
|
+
expect(subject).to match(/spec\/rutabaga\/util\.rutabaga\Z/)
|
74
|
+
end
|
75
|
+
|
76
|
+
it "handles paths with spaces" do
|
77
|
+
@description = '/User/person/Internet plugins/feature.feature'
|
78
|
+
allow(File).to receive(:exists?).with(@description).and_return(true)
|
79
|
+
|
80
|
+
expect(subject).to eq(@description)
|
81
|
+
end
|
82
|
+
|
83
|
+
it "allows the .feature extension" do
|
84
|
+
@description = "example.feature"
|
85
|
+
allow(File).to receive(:exists?).with(@description).and_return(true)
|
86
|
+
|
87
|
+
expect(subject).to include(@description)
|
88
|
+
end
|
89
|
+
|
90
|
+
it "allows the .rutabaga extension" do
|
91
|
+
@description = "example.rutabaga"
|
92
|
+
allow(File).to receive(:exists?).with(@description).and_return(true)
|
93
|
+
|
94
|
+
expect(subject).to include(@description)
|
95
|
+
end
|
96
|
+
|
97
|
+
end
|
98
|
+
|
99
|
+
describe "raises an error if the feature cannot be found" do
|
100
|
+
before do
|
101
|
+
allow(File).to receive(:exists?).and_return(false)
|
102
|
+
end
|
103
|
+
|
104
|
+
it "has a nil description" do
|
105
|
+
@description = nil
|
106
|
+
|
107
|
+
expect{subject}.to raise_error(/Feature file not found\. Tried: [\\\/\w]*\/spec\/rutabaga\/util\.feature/)
|
108
|
+
end
|
109
|
+
|
110
|
+
it "has a sentance description" do
|
111
|
+
@description = "my life as a dog"
|
112
|
+
|
113
|
+
expect{subject}.to raise_error(/Feature file not found\. Tried: [\\\/\w]*\/spec\/rutabaga\/util\.feature/)
|
114
|
+
end
|
115
|
+
|
116
|
+
it "has a filename description but the file doesn't exist" do
|
117
|
+
@description = "example.feature"
|
118
|
+
|
119
|
+
expect{subject}.to raise_error(/Feature file not found\. Tried: example\.feature, [\\\/\w]*example\.feature/)
|
120
|
+
end
|
121
|
+
|
122
|
+
it "raises an error if the filename does not end in feature" do
|
123
|
+
@description = "example.other"
|
124
|
+
allow(File).to receive(:exists?).with(@description).and_return(true)
|
125
|
+
|
126
|
+
expect{subject}.to raise_error(/Feature file not found\. Tried: [\\\/\w]*\/spec\/rutabaga\/util\.feature/)
|
127
|
+
end
|
128
|
+
end
|
129
|
+
end
|
130
|
+
end
|
metadata
CHANGED
@@ -1,29 +1,85 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: rutabaga
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version:
|
4
|
+
version: 2.0.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Lukas Oberhuber
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2016-05-20 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: turnip
|
15
15
|
requirement: !ruby/object:Gem::Requirement
|
16
16
|
requirements:
|
17
|
-
- - "
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: 2.0.0
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: 2.0.0
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: gherkin
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
18
32
|
- !ruby/object:Gem::Version
|
19
33
|
version: '2.0'
|
20
34
|
type: :runtime
|
21
35
|
prerelease: false
|
22
36
|
version_requirements: !ruby/object:Gem::Requirement
|
23
37
|
requirements:
|
24
|
-
- - "
|
38
|
+
- - "~>"
|
25
39
|
- !ruby/object:Gem::Version
|
26
40
|
version: '2.0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: activesupport
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - ">="
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '0'
|
48
|
+
type: :runtime
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - ">="
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: rspec-mocks
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - "<="
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: 3.4.0
|
62
|
+
type: :runtime
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - "<="
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: 3.4.0
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: capybara
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - ">="
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '0'
|
76
|
+
type: :development
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - ">="
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '0'
|
27
83
|
- !ruby/object:Gem::Dependency
|
28
84
|
name: pry
|
29
85
|
requirement: !ruby/object:Gem::Requirement
|
@@ -52,17 +108,24 @@ files:
|
|
52
108
|
- LICENSE
|
53
109
|
- README.md
|
54
110
|
- Rakefile
|
111
|
+
- examples/compatibility/compatibility_spec.rb
|
55
112
|
- examples/spec_helper.rb
|
56
113
|
- examples/test.feature
|
57
114
|
- examples/test2.feature
|
58
115
|
- examples/test3.feature
|
59
116
|
- examples/test_background.feature
|
117
|
+
- examples/test_feature_example_group.feature
|
118
|
+
- examples/test_feature_example_group_spec.rb
|
60
119
|
- examples/test_spec.rb
|
61
120
|
- lib/rutabaga.rb
|
121
|
+
- lib/rutabaga/example_group/feature.rb
|
62
122
|
- lib/rutabaga/feature.rb
|
123
|
+
- lib/rutabaga/util.rb
|
63
124
|
- lib/rutabaga/version.rb
|
125
|
+
- rutabaga-vs-turnip.jpg
|
64
126
|
- rutabaga.gemspec
|
65
127
|
- spec/feature_spec.rb
|
128
|
+
- spec/rutabaga/util_spec.rb
|
66
129
|
- spec/spec_helper.rb
|
67
130
|
homepage: https://github.com/simplybusiness/rutabaga
|
68
131
|
licenses:
|
@@ -84,12 +147,13 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
84
147
|
version: '0'
|
85
148
|
requirements: []
|
86
149
|
rubyforge_project:
|
87
|
-
rubygems_version: 2.4.5
|
150
|
+
rubygems_version: 2.4.5.1
|
88
151
|
signing_key:
|
89
152
|
specification_version: 4
|
90
153
|
summary: Calling Turnip feature files from RSpec, which allows encapsulating a feature
|
91
154
|
inside a describe block
|
92
155
|
test_files:
|
93
156
|
- spec/feature_spec.rb
|
157
|
+
- spec/rutabaga/util_spec.rb
|
94
158
|
- spec/spec_helper.rb
|
95
159
|
has_rdoc:
|