guard-cucumber 0.6.2 → 0.6.3
Sign up to get free protection for your applications and to get access to all the features.
- data/README.md +54 -69
- data/lib/guard/cucumber.rb +55 -12
- data/lib/guard/cucumber/inspector.rb +35 -1
- data/lib/guard/cucumber/notification_formatter.rb +44 -0
- data/lib/guard/cucumber/runner.rb +32 -1
- data/lib/guard/cucumber/version.rb +2 -1
- metadata +36 -9
- data/lib/guard/cucumber.rbc +0 -1753
- data/lib/guard/cucumber/inspector.rbc +0 -1216
- data/lib/guard/cucumber/notification_formatter.rbc +0 -966
- data/lib/guard/cucumber/runner.rbc +0 -1256
- data/lib/guard/cucumber/version.rbc +0 -203
data/README.md
CHANGED
@@ -1,10 +1,8 @@
|
|
1
|
-
# Guard::Cucumber
|
2
|
-
|
3
|
-
![travis-ci](http://travis-ci.org/netzpirat/guard-cucumber.png)
|
1
|
+
# Guard::Cucumber [![Build Status](https://secure.travis-ci.org/netzpirat/guard-cucumber.png)](http://travis-ci.org/netzpirat/guard-cucumber)
|
4
2
|
|
5
3
|
Guard::Cucumber allows you to automatically run Cucumber features when files are modified.
|
6
4
|
|
7
|
-
Tested on MRI Ruby 1.8.7, 1.9.2 and the latest versions of JRuby & Rubinius.
|
5
|
+
Tested on MRI Ruby 1.8.7, 1.9.2, REE and the latest versions of JRuby & Rubinius.
|
8
6
|
|
9
7
|
If you have any questions please join us on our [Google group](http://groups.google.com/group/guard-dev) or on `#guard` (irc.freenode.net).
|
10
8
|
|
@@ -14,21 +12,15 @@ Please be sure to have [Guard](https://github.com/guard/guard) installed before
|
|
14
12
|
|
15
13
|
Install the gem:
|
16
14
|
|
17
|
-
|
18
|
-
$ gem install guard-cucumber
|
19
|
-
```
|
15
|
+
$ gem install guard-cucumber
|
20
16
|
|
21
17
|
Add it to your `Gemfile`, preferably inside the test group:
|
22
18
|
|
23
|
-
|
24
|
-
gem 'guard-cucumber'
|
25
|
-
```
|
19
|
+
gem 'guard-cucumber'
|
26
20
|
|
27
21
|
Add the default Guard::Cucumber template to your `Guardfile` by running this command:
|
28
22
|
|
29
|
-
|
30
|
-
$ guard init cucumber
|
31
|
-
```
|
23
|
+
$ guard init cucumber
|
32
24
|
|
33
25
|
## Usage
|
34
26
|
|
@@ -38,13 +30,11 @@ Please read the [Guard usage documentation](https://github.com/guard/guard#readm
|
|
38
30
|
|
39
31
|
Guard::Cucumber can be adapted to all kind of projects and comes with a default template that looks like this:
|
40
32
|
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
end
|
47
|
-
```
|
33
|
+
guard 'cucumber' do
|
34
|
+
watch(%r{^features/.+\.feature$})
|
35
|
+
watch(%r{^features/support/.+$}) { 'features' }
|
36
|
+
watch(%r{^features/step_definitions/(.+)_steps\.rb$}) { |m| Dir[File.join("**/#{m[1]}.feature")][0] || 'features' }
|
37
|
+
end
|
48
38
|
|
49
39
|
Expressed in plain English, this configuration tells Guard::Cucumber:
|
50
40
|
|
@@ -60,44 +50,39 @@ Please read the [Guard documentation](http://github.com/guard/guard#readme) for
|
|
60
50
|
|
61
51
|
You can pass any of the standard Cucumber CLI options using the :cli option:
|
62
52
|
|
63
|
-
|
64
|
-
guard 'cucumber', :cli => '-c --drb --port 1234 --profile guard' do
|
65
|
-
end
|
66
|
-
```
|
53
|
+
guard 'cucumber', :cli => '-c --drb --port 1234 --profile guard'
|
67
54
|
|
68
55
|
Former `:color`, `:drb`, `:port` and `:profile` options are thus deprecated and have no effect anymore.
|
69
56
|
|
70
57
|
### List of available options
|
71
58
|
|
72
|
-
|
73
|
-
:
|
74
|
-
# default: '--no-profile --color --format progress --strict'
|
59
|
+
:cli => '--profile guard -c' # Pass arbitrary Cucumber CLI arguments,
|
60
|
+
# default: '--no-profile --color --format progress --strict'
|
75
61
|
|
76
|
-
:bundler => false # Don't use "bundle exec" to run the Cucumber command
|
77
|
-
|
62
|
+
:bundler => false # Don't use "bundle exec" to run the Cucumber command
|
63
|
+
# default: true
|
78
64
|
|
79
|
-
:rvm => ['1.8.7', '1.9.2'] # Directly run your features on multiple ruby versions
|
80
|
-
|
65
|
+
:rvm => ['1.8.7', '1.9.2'] # Directly run your features on multiple ruby versions
|
66
|
+
# default: nil
|
81
67
|
|
82
|
-
:notification => false # Don't display Growl (or Libnotify) notification
|
83
|
-
|
68
|
+
:notification => false # Don't display Growl (or Libnotify) notification
|
69
|
+
# default: true
|
84
70
|
|
85
|
-
:all_after_pass => false # Don't run all features after changed features pass
|
86
|
-
|
71
|
+
:all_after_pass => false # Don't run all features after changed features pass
|
72
|
+
# default: true
|
87
73
|
|
88
|
-
:all_on_start => false # Don't run all the features at startup
|
89
|
-
|
74
|
+
:all_on_start => false # Don't run all the features at startup
|
75
|
+
# default: true
|
90
76
|
|
91
|
-
:keep_failed => false # Keep failed features until
|
92
|
-
|
77
|
+
:keep_failed => false # Keep failed features until they pass
|
78
|
+
# default: true
|
93
79
|
|
94
|
-
:run_all => { :cli => "-p" } # Override any option when running all specs
|
95
|
-
|
80
|
+
:run_all => { :cli => "-p" } # Override any option when running all specs
|
81
|
+
# default: {}
|
96
82
|
|
97
|
-
:change_format => 'pretty' # Use a different cucumber format when running individual features
|
98
|
-
|
99
|
-
|
100
|
-
```
|
83
|
+
:change_format => 'pretty' # Use a different cucumber format when running individual features
|
84
|
+
# This replaces the Cucumber --format option within the :cli option
|
85
|
+
# default: nil
|
101
86
|
|
102
87
|
## Cucumber configuration
|
103
88
|
|
@@ -117,9 +102,7 @@ If you want to configure Cucumber from Guard solely, then you should pass `--no-
|
|
117
102
|
|
118
103
|
Since guard-cucumber version 0.3.2, the default `:cli` options are:
|
119
104
|
|
120
|
-
|
121
|
-
:cli => '--no-profile --color --format progress --strict'
|
122
|
-
```
|
105
|
+
:cli => '--no-profile --color --format progress --strict'
|
123
106
|
|
124
107
|
This default configuration has been chosen to avoid strange behavior when mixing configurations form
|
125
108
|
the cucumber.yml default profile with the guard-cucumber `:cli` option.
|
@@ -131,9 +114,7 @@ You can safely remove `config/cucumber.yml`, since all configuration is done in
|
|
131
114
|
If you're using different profiles with Cucumber then you should create a profile for Guard in cucumber.yml,
|
132
115
|
something like this:
|
133
116
|
|
134
|
-
|
135
|
-
guard: --format progress --strict --tags ~@wip
|
136
|
-
```
|
117
|
+
guard: --format progress --strict --tags ~@wip
|
137
118
|
|
138
119
|
Now you want to make guard-cucumber use that profile by passing '--profile guard' to the `:cli`.
|
139
120
|
|
@@ -142,30 +123,34 @@ Now you want to make guard-cucumber use that profile by passing '--profile guard
|
|
142
123
|
To use Guard::Cucumber with [Spork](https://github.com/timcharper/spork), you should install
|
143
124
|
[Guard::Spork](https://github.com/guard/guard-spork) and use the following configuration:
|
144
125
|
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
end
|
159
|
-
```
|
126
|
+
guard 'spork' do
|
127
|
+
watch('config/application.rb')
|
128
|
+
watch('config/environment.rb')
|
129
|
+
watch(%r{^config/environments/.*\.rb$})
|
130
|
+
watch(%r{^config/initializers/.*\.rb$})
|
131
|
+
watch('spec/spec_helper.rb')
|
132
|
+
end
|
133
|
+
|
134
|
+
guard 'cucumber', :cli => '--drb --format progress --no-profile' do
|
135
|
+
watch(%r{^features/.+\.feature$})
|
136
|
+
watch(%r{^features/support/.+$}) { 'features' }
|
137
|
+
watch(%r{^features/step_definitions/(.+)_steps\.rb$}) { |m| Dir[File.join("**/#{m[1]}.feature")][0] || 'features' }
|
138
|
+
end
|
160
139
|
|
161
140
|
There is a section with alternative configurations on the [Wiki](https://github.com/netzpirat/guard-cucumber/wiki/Spork-configurations).
|
162
141
|
|
163
142
|
## Development
|
164
143
|
|
165
|
-
-
|
166
|
-
-
|
144
|
+
- Documentation hosted at [RubyDoc](http://rubydoc.info/gems/guard-cucumber/frames).
|
145
|
+
- Source hosted at [GitHub](https://github.com/netzpirat/guard-cucumber).
|
146
|
+
- Report issues and feature requests to [GitHub Issues](https://github.com/netzpirat/guard-cucumber/issues).
|
147
|
+
|
148
|
+
Pull requests are very welcome! Please try to follow these simple "rules", though:
|
167
149
|
|
168
|
-
|
150
|
+
- Please create a topic branch for every separate change you make.
|
151
|
+
- Make sure your patches are well tested.
|
152
|
+
- Update the README (if applicable).
|
153
|
+
- Please **do not change** the version number.
|
169
154
|
|
170
155
|
For questions please join us on our [Google group](http://groups.google.com/group/guard-dev) or on `#guard` (irc.freenode.net).
|
171
156
|
|
data/lib/guard/cucumber.rb
CHANGED
@@ -3,30 +3,56 @@ require 'guard/guard'
|
|
3
3
|
require 'cucumber'
|
4
4
|
|
5
5
|
module Guard
|
6
|
+
|
7
|
+
# The Cucumber guard that gets notifications about the following
|
8
|
+
# Guard events: `start`, `stop`, `reload`, `run_all` and `run_on_change`.
|
9
|
+
#
|
6
10
|
class Cucumber < Guard
|
7
11
|
|
8
12
|
autoload :Runner, 'guard/cucumber/runner'
|
9
13
|
autoload :Inspector, 'guard/cucumber/inspector'
|
10
14
|
|
11
|
-
|
15
|
+
# Initialize Guard::Cucumber.
|
16
|
+
#
|
17
|
+
# @param [Array<Guard::Watcher>] watchers the watchers in the Guard block
|
18
|
+
# @param [Hash] options the options for the Guard
|
19
|
+
# @option options [String] :cli any arbitrary Cucumber CLI arguments
|
20
|
+
# @option options [Boolean] :bundler use bundler or not
|
21
|
+
# @option options [Array<String>] :rvm a list of rvm version to use for the test
|
22
|
+
# @option options [Boolean] :notification show notifications
|
23
|
+
# @option options [Boolean] :all_after_pass run all features after changed features pass
|
24
|
+
# @option options [Boolean] :all_on_start run all the features at startup
|
25
|
+
# @option options [Boolean] :keep_failed Keep failed features until they pass
|
26
|
+
# @option options [Boolean] :run_all run override any option when running all specs
|
27
|
+
# @option options [Boolean] :change_format use a different cucumber format when running individual features
|
28
|
+
#
|
29
|
+
def initialize(watchers = [], options = { })
|
12
30
|
super
|
13
31
|
@options = {
|
14
32
|
:all_after_pass => true,
|
15
|
-
:all_on_start
|
16
|
-
:keep_failed
|
17
|
-
:cli
|
33
|
+
:all_on_start => true,
|
34
|
+
:keep_failed => true,
|
35
|
+
:cli => '--no-profile --color --format progress --strict'
|
18
36
|
}.update(options)
|
19
37
|
|
20
|
-
@last_failed
|
38
|
+
@last_failed = false
|
21
39
|
@failed_paths = []
|
22
40
|
end
|
23
41
|
|
42
|
+
# Gets called once when Guard starts.
|
43
|
+
#
|
44
|
+
# @return [Boolean] when the start was successful
|
45
|
+
#
|
24
46
|
def start
|
25
47
|
run_all if @options[:all_on_start]
|
26
48
|
end
|
27
49
|
|
50
|
+
# Gets called when all specs should be run.
|
51
|
+
#
|
52
|
+
# @return [Boolean] when running all specs was successful
|
53
|
+
#
|
28
54
|
def run_all
|
29
|
-
passed = Runner.run(['features'], options.merge(options[:run_all] || {}).merge(:message => 'Running all features'))
|
55
|
+
passed = Runner.run(['features'], options.merge(options[:run_all] || { }).merge(:message => 'Running all features'))
|
30
56
|
|
31
57
|
if passed
|
32
58
|
@failed_paths = []
|
@@ -35,21 +61,30 @@ module Guard
|
|
35
61
|
end
|
36
62
|
|
37
63
|
@last_failed = !passed
|
38
|
-
|
64
|
+
|
39
65
|
passed
|
40
66
|
end
|
41
67
|
|
68
|
+
# Gets called when the Guard should reload itself.
|
69
|
+
#
|
70
|
+
# @return [Boolean] when reloading was successful
|
71
|
+
#
|
42
72
|
def reload
|
43
73
|
@failed_paths = []
|
44
|
-
|
74
|
+
|
45
75
|
true
|
46
76
|
end
|
47
77
|
|
78
|
+
# Gets called when watched paths and files have changes.
|
79
|
+
#
|
80
|
+
# @param [Array<String>] paths the changed paths and files
|
81
|
+
# @return [Boolean] when running the changed specs was successful
|
82
|
+
#
|
48
83
|
def run_on_change(paths)
|
49
84
|
paths += @failed_paths if @options[:keep_failed]
|
50
|
-
paths
|
85
|
+
paths = Inspector.clean(paths)
|
51
86
|
options = @options[:change_format] ? change_format(@options[:change_format]) : @options
|
52
|
-
passed
|
87
|
+
passed = Runner.run(paths, paths.include?('features') ? options.merge({ :message => 'Running all features' }) : options)
|
53
88
|
|
54
89
|
if passed
|
55
90
|
# clean failed paths memory
|
@@ -62,12 +97,15 @@ module Guard
|
|
62
97
|
# track whether the changed feature failed for the next change
|
63
98
|
@last_failed = true
|
64
99
|
end
|
65
|
-
|
66
|
-
passed
|
67
100
|
end
|
68
101
|
|
69
102
|
private
|
70
103
|
|
104
|
+
# Read the failed features that from `rerun.txt`
|
105
|
+
#
|
106
|
+
# @see Guard::Cucumber::NotificationFormatter#write_rerun_features
|
107
|
+
# @return [Array<String>] the list of features
|
108
|
+
#
|
71
109
|
def read_failed_features
|
72
110
|
failed = []
|
73
111
|
|
@@ -79,6 +117,11 @@ module Guard
|
|
79
117
|
failed
|
80
118
|
end
|
81
119
|
|
120
|
+
# Change the `--format` cli option.
|
121
|
+
#
|
122
|
+
# @param [String] format the new format
|
123
|
+
# @return [Hash] the new options
|
124
|
+
#
|
82
125
|
def change_format(format)
|
83
126
|
cli_parts = @options[:cli].split(" ")
|
84
127
|
cli_parts.each_with_index do |part, index|
|
@@ -1,8 +1,18 @@
|
|
1
1
|
module Guard
|
2
2
|
class Cucumber
|
3
|
+
|
4
|
+
# The inspector verifies of the changed paths are valid
|
5
|
+
# for Guard::Cucumber.
|
6
|
+
#
|
3
7
|
module Inspector
|
4
8
|
class << self
|
5
9
|
|
10
|
+
# Clean the changed paths and return only valid
|
11
|
+
# Cucumber features.
|
12
|
+
#
|
13
|
+
# @param [Array<String>] paths the changed paths
|
14
|
+
# @return [Array<String>] the valid feature files
|
15
|
+
#
|
6
16
|
def clean(paths)
|
7
17
|
paths.uniq!
|
8
18
|
paths.compact!
|
@@ -12,24 +22,48 @@ module Guard
|
|
12
22
|
paths
|
13
23
|
end
|
14
24
|
|
15
|
-
|
25
|
+
private
|
16
26
|
|
27
|
+
# Tests if the file is the features folder.
|
28
|
+
#
|
29
|
+
# @param [String] file the file
|
30
|
+
# @return [Boolean] when the file is the feature folder
|
31
|
+
#
|
17
32
|
def cucumber_folder?(path)
|
18
33
|
path.match(/^\/?features/) && !path.match(/\..+$/)
|
19
34
|
end
|
20
35
|
|
36
|
+
# Tests if the file is valid.
|
37
|
+
#
|
38
|
+
# @param [String] file the file
|
39
|
+
# @return [Boolean] when the file valid
|
40
|
+
#
|
21
41
|
def cucumber_file?(path)
|
22
42
|
cucumber_files.include?(path.split(':').first)
|
23
43
|
end
|
24
44
|
|
45
|
+
# Scans the project and keeps a list of all
|
46
|
+
# feature files in the `features` directory.
|
47
|
+
#
|
48
|
+
# @see #clear_jasmine_specs
|
49
|
+
# @return [Array<String>] the valid files
|
50
|
+
#
|
25
51
|
def cucumber_files
|
26
52
|
@cucumber_files ||= Dir.glob('features/**/*.feature')
|
27
53
|
end
|
28
54
|
|
55
|
+
# Clears the list of features in this project.
|
56
|
+
#
|
29
57
|
def clear_cucumber_files_list
|
30
58
|
@cucumber_files = nil
|
31
59
|
end
|
32
60
|
|
61
|
+
# Checks if the given path is already contained
|
62
|
+
# in the paths list.
|
63
|
+
#
|
64
|
+
# @param [Sting] path the path to test
|
65
|
+
# @param [Array<String>] paths the list of paths
|
66
|
+
#
|
33
67
|
def included_in_other_path?(path, paths)
|
34
68
|
paths = paths.select { |p| p != path }
|
35
69
|
paths.any? { |p| path.include?(p) && (path.gsub(p, '')).include?('/') }
|
@@ -5,27 +5,52 @@ require 'cucumber/formatter/io'
|
|
5
5
|
|
6
6
|
module Guard
|
7
7
|
class Cucumber
|
8
|
+
|
9
|
+
# The notification formatter is a Cucumber formatter that Guard::Cucumber
|
10
|
+
# passes to the Cucumber binary. It writes the `rerun.txt` file with the failed features
|
11
|
+
# an creates system notifications.
|
12
|
+
#
|
13
|
+
# @see https://github.com/cucumber/cucumber/wiki/Custom-Formatters
|
14
|
+
#
|
8
15
|
class NotificationFormatter
|
9
16
|
include ::Cucumber::Formatter::Console
|
10
17
|
|
11
18
|
attr_reader :step_mother
|
12
19
|
|
20
|
+
# Initialize the formatter.
|
21
|
+
#
|
22
|
+
# @param [Cucumber::Runtime] step_mother the step mother
|
23
|
+
# @param [String, IO] path_or_io the path or IO to the feature file
|
24
|
+
# @param [Hash] options the options
|
25
|
+
#
|
13
26
|
def initialize(step_mother, path_or_io, options)
|
14
27
|
@options = options
|
15
28
|
@file_names = []
|
16
29
|
@step_mother = step_mother
|
17
30
|
end
|
18
31
|
|
32
|
+
# Notification after all features have completed.
|
33
|
+
#
|
34
|
+
# @param [Array[Cucumber::Ast::Feature]] features the ran features
|
35
|
+
#
|
19
36
|
def after_features(features)
|
20
37
|
notify_summary
|
21
38
|
write_rerun_features if !@file_names.empty?
|
22
39
|
end
|
23
40
|
|
41
|
+
# Before a feature gets run.
|
42
|
+
#
|
43
|
+
# @param [Cucumber::Ast::FeatureElement] feature_element
|
44
|
+
#
|
24
45
|
def before_feature_element(feature_element)
|
25
46
|
@rerun = false
|
26
47
|
@feature_name = feature_element.name
|
27
48
|
end
|
28
49
|
|
50
|
+
# After a feature gets run.
|
51
|
+
#
|
52
|
+
# @param [Cucumber::Ast::FeatureElement] feature_element
|
53
|
+
#
|
29
54
|
def after_feature_element(feature_element)
|
30
55
|
if @rerun
|
31
56
|
@file_names << feature_element.file_colon_line
|
@@ -33,16 +58,28 @@ module Guard
|
|
33
58
|
end
|
34
59
|
end
|
35
60
|
|
61
|
+
# Gets called when a step is done.
|
62
|
+
#
|
63
|
+
# @param [String] keyword the keyword
|
64
|
+
# @param [Cucumber::StepMatch] step_match the step match
|
65
|
+
# @param [Symbol] status the status of the step
|
66
|
+
# @param [Integer] source_indent the source indentation
|
67
|
+
# @param [Cucumber::Ast::Background] background the feature background
|
68
|
+
#
|
36
69
|
def step_name(keyword, step_match, status, source_indent, background)
|
37
70
|
if [:failed, :pending, :undefined].index(status)
|
38
71
|
@rerun = true
|
39
72
|
step_name = step_match.format_args(lambda { |param| "*#{ param }*" })
|
73
|
+
|
40
74
|
::Guard::Notifier.notify step_name, :title => @feature_name, :image => icon_for(status)
|
41
75
|
end
|
42
76
|
end
|
43
77
|
|
44
78
|
private
|
45
79
|
|
80
|
+
# Notify the user with a system notification about the
|
81
|
+
# result of the feature tests.
|
82
|
+
#
|
46
83
|
def notify_summary
|
47
84
|
icon, messages = nil, []
|
48
85
|
|
@@ -57,12 +94,19 @@ module Guard
|
|
57
94
|
::Guard::Notifier.notify messages.reverse.join(', '), :title => 'Cucumber Results', :image => icon
|
58
95
|
end
|
59
96
|
|
97
|
+
# Writes the `rerun.txt` file containing all failed features.
|
98
|
+
#
|
60
99
|
def write_rerun_features
|
61
100
|
File.open('rerun.txt', 'w') do |f|
|
62
101
|
f.puts @file_names.join(' ')
|
63
102
|
end
|
64
103
|
end
|
65
104
|
|
105
|
+
# Gives the icon name to use for the status.
|
106
|
+
#
|
107
|
+
# @param [Symbol] status the cucumber status
|
108
|
+
# @return [Symbol] the Guard notification symbol
|
109
|
+
#
|
66
110
|
def icon_for(status)
|
67
111
|
case status
|
68
112
|
when :passed
|