guard-rspec 4.0.4 → 4.1.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.
- checksums.yaml +4 -4
- data/.gitignore +2 -0
- data/.travis.yml +5 -1
- data/README.md +12 -9
- data/lib/guard/rspec.rb +3 -6
- data/lib/guard/rspec/command.rb +6 -19
- data/lib/guard/rspec/deprecator.rb +13 -1
- data/lib/guard/rspec/formatter.rb +36 -0
- data/lib/guard/rspec/inspectors/base_inspector.rb +52 -0
- data/lib/guard/rspec/inspectors/factory.rb +24 -0
- data/lib/guard/rspec/inspectors/focused_inspector.rb +39 -0
- data/lib/guard/rspec/inspectors/keeping_inspector.rb +96 -0
- data/lib/guard/rspec/inspectors/simple_inspector.rb +21 -0
- data/lib/guard/rspec/notifier.rb +52 -0
- data/lib/guard/rspec/options.rb +34 -0
- data/lib/guard/rspec/runner.rb +40 -31
- data/lib/guard/rspec/version.rb +1 -1
- data/spec/lib/guard/rspec/command_spec.rb +2 -6
- data/spec/lib/guard/rspec/deprecator_spec.rb +21 -2
- data/spec/lib/guard/rspec/formatter_spec.rb +42 -0
- data/spec/lib/guard/rspec/inspectors/base_inspector_spec.rb +34 -0
- data/spec/lib/guard/rspec/inspectors/factory_spec.rb +40 -0
- data/spec/lib/guard/rspec/inspectors/focused_inspector_spec.rb +74 -0
- data/spec/lib/guard/rspec/inspectors/keeping_inspector_spec.rb +122 -0
- data/spec/lib/guard/rspec/inspectors/shared_examples.rb +59 -0
- data/spec/lib/guard/rspec/inspectors/simple_inspector_spec.rb +23 -0
- data/spec/lib/guard/rspec/notifier_spec.rb +69 -0
- data/spec/lib/guard/rspec/runner_spec.rb +75 -66
- data/spec/lib/guard/rspec_spec.rb +8 -3
- metadata +25 -12
- data/lib/guard/rspec/formatters/focuser.rb +0 -29
- data/lib/guard/rspec/formatters/notifier.rb +0 -48
- data/lib/guard/rspec/inspector.rb +0 -78
- data/spec/lib/guard/rspec/formatters/focuser_spec.rb +0 -25
- data/spec/lib/guard/rspec/formatters/notifier_spec.rb +0 -44
- data/spec/lib/guard/rspec/inspector_spec.rb +0 -107
@@ -0,0 +1,52 @@
|
|
1
|
+
module Guard
|
2
|
+
class RSpec
|
3
|
+
class Notifier
|
4
|
+
attr_accessor :options
|
5
|
+
|
6
|
+
def initialize(options = {})
|
7
|
+
@options = options
|
8
|
+
end
|
9
|
+
|
10
|
+
TITLE = 'RSpec results'
|
11
|
+
|
12
|
+
def notify(summary)
|
13
|
+
return unless options[:notification]
|
14
|
+
failure_count, pending_count = _parse_summary(summary)
|
15
|
+
image = _image(failure_count, pending_count)
|
16
|
+
priority = _priority(image)
|
17
|
+
::Guard::Notifier.notify(summary, title: TITLE, image: image, priority: priority)
|
18
|
+
end
|
19
|
+
|
20
|
+
def notify_failure
|
21
|
+
return unless options[:notification]
|
22
|
+
::Guard::Notifier.notify('Failed', title: TITLE, image: :failed, priority: 2)
|
23
|
+
end
|
24
|
+
|
25
|
+
private
|
26
|
+
|
27
|
+
def _parse_summary(summary)
|
28
|
+
summary.match(/(\d+) failures( \((\d+) pending\))?/) do |m|
|
29
|
+
return m[1].to_i, m[3].to_i
|
30
|
+
end
|
31
|
+
[0, 0]
|
32
|
+
end
|
33
|
+
|
34
|
+
def _image(failure_count, pending_count)
|
35
|
+
if failure_count > 0
|
36
|
+
:failed
|
37
|
+
elsif pending_count > 0
|
38
|
+
:pending
|
39
|
+
else
|
40
|
+
:success
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
def _priority(image)
|
45
|
+
{ failed: 2,
|
46
|
+
pending: -1,
|
47
|
+
success: -2
|
48
|
+
}[image]
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
module Guard
|
2
|
+
class RSpec
|
3
|
+
module Options
|
4
|
+
DEFAULTS = {
|
5
|
+
all_on_start: false,
|
6
|
+
all_after_pass: false,
|
7
|
+
run_all: { message: 'Running all specs' },
|
8
|
+
failed_mode: :focus, # :keep and :none are other posibilities
|
9
|
+
spec_paths: %w[spec],
|
10
|
+
cmd: 'rspec',
|
11
|
+
launchy: nil,
|
12
|
+
notification: true
|
13
|
+
}.freeze
|
14
|
+
|
15
|
+
class << self
|
16
|
+
def with_defaults(options = {})
|
17
|
+
_deep_merge(DEFAULTS, options).freeze
|
18
|
+
end
|
19
|
+
|
20
|
+
private
|
21
|
+
|
22
|
+
def _deep_merge(hash1, hash2)
|
23
|
+
hash1.merge(hash2) do |key, oldval, newval|
|
24
|
+
if oldval.instance_of?(Hash) && newval.instance_of?(Hash)
|
25
|
+
_deep_merge(oldval, newval)
|
26
|
+
else
|
27
|
+
newval
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
data/lib/guard/rspec/runner.rb
CHANGED
@@ -1,51 +1,56 @@
|
|
1
|
+
require 'guard/rspec/inspectors/factory'
|
1
2
|
require 'guard/rspec/command'
|
2
|
-
require 'guard/rspec/
|
3
|
+
require 'guard/rspec/formatter'
|
4
|
+
require 'guard/rspec/notifier'
|
3
5
|
|
4
6
|
module Guard
|
5
7
|
class RSpec
|
6
8
|
class Runner
|
7
|
-
attr_accessor :options, :inspector
|
9
|
+
attr_accessor :options, :inspector, :notifier
|
8
10
|
|
9
11
|
def initialize(options = {})
|
10
|
-
@options =
|
11
|
-
|
12
|
-
|
13
|
-
run_all: { message: 'Running all specs' },
|
14
|
-
launchy: nil
|
15
|
-
}.merge(options)
|
16
|
-
|
17
|
-
@inspector = Inspector.new(@options)
|
12
|
+
@options = options
|
13
|
+
@inspector = Inspectors::Factory.create(@options)
|
14
|
+
@notifier = Notifier.new(@options)
|
18
15
|
end
|
19
16
|
|
20
17
|
def run_all
|
21
|
-
|
18
|
+
paths = options[:spec_paths]
|
19
|
+
options = @options.merge(@options[:run_all]).freeze
|
20
|
+
return if paths.empty?
|
22
21
|
::Guard::UI.info(options[:message], reset: true)
|
23
|
-
|
24
|
-
_run(inspector.paths, [], options)
|
22
|
+
_run(true, paths, options)
|
25
23
|
end
|
26
24
|
|
27
25
|
def run(paths)
|
28
|
-
failed_paths = inspector.failed_paths
|
29
26
|
paths = inspector.paths(paths)
|
30
27
|
return if paths.empty?
|
31
|
-
|
32
28
|
::Guard::UI.info("Running: #{paths.join(' ')}", reset: true)
|
33
|
-
|
34
|
-
_run(paths, failed_paths, options)
|
29
|
+
_run(false, paths, options)
|
35
30
|
end
|
36
31
|
|
37
32
|
def reload
|
38
|
-
inspector.
|
33
|
+
inspector.reload
|
39
34
|
end
|
40
35
|
|
41
36
|
private
|
42
37
|
|
43
|
-
def _run(
|
38
|
+
def _run(all, paths, options)
|
44
39
|
command = Command.new(paths, options)
|
45
40
|
_without_bundler_env { Kernel.system(command) }.tap do |success|
|
46
|
-
|
47
|
-
|
48
|
-
|
41
|
+
if _command_success?(success)
|
42
|
+
summary, failed_paths = _command_output
|
43
|
+
if summary && failed_paths
|
44
|
+
inspector.failed(failed_paths)
|
45
|
+
notifier.notify(summary)
|
46
|
+
_open_launchy
|
47
|
+
_run_all_after_pass if !all && success
|
48
|
+
else
|
49
|
+
notifier.notify_failure
|
50
|
+
end
|
51
|
+
else
|
52
|
+
notifier.notify_failure
|
53
|
+
end
|
49
54
|
end
|
50
55
|
end
|
51
56
|
|
@@ -57,14 +62,19 @@ module Guard
|
|
57
62
|
end
|
58
63
|
end
|
59
64
|
|
60
|
-
def
|
61
|
-
return
|
62
|
-
|
63
|
-
::Guard::Notifier.notify('Failed', title: 'RSpec results', image: :failed, priority: 2)
|
65
|
+
def _command_success?(success)
|
66
|
+
return false if success.nil?
|
67
|
+
[Command::FAILURE_EXIT_CODE, 0].include?($?.exitstatus)
|
64
68
|
end
|
65
69
|
|
66
|
-
def
|
67
|
-
|
70
|
+
def _command_output
|
71
|
+
formatter_tmp_file = Formatter::TEMPORARY_FILE_PATH
|
72
|
+
lines = File.readlines(formatter_tmp_file)
|
73
|
+
[lines.first.strip, lines[1..11].map(&:strip).compact]
|
74
|
+
rescue
|
75
|
+
[nil, nil]
|
76
|
+
ensure
|
77
|
+
File.exist?(formatter_tmp_file) && File.delete(formatter_tmp_file)
|
68
78
|
end
|
69
79
|
|
70
80
|
def _open_launchy
|
@@ -74,11 +84,10 @@ module Guard
|
|
74
84
|
::Launchy.open(options[:launchy]) if pn.exist?
|
75
85
|
end
|
76
86
|
|
77
|
-
def _run_all_after_pass
|
87
|
+
def _run_all_after_pass
|
78
88
|
return unless options[:all_after_pass]
|
79
|
-
run_all
|
89
|
+
run_all
|
80
90
|
end
|
81
|
-
|
82
91
|
end
|
83
92
|
end
|
84
93
|
end
|
data/lib/guard/rspec/version.rb
CHANGED
@@ -16,12 +16,8 @@ describe Guard::RSpec::Command do
|
|
16
16
|
expect(command).to match /--failure-exit-code 2/
|
17
17
|
end
|
18
18
|
|
19
|
-
it "sets
|
20
|
-
expect(command).to match %r{-r .*/lib/guard/rspec/
|
21
|
-
end
|
22
|
-
|
23
|
-
it "sets focuser formatter" do
|
24
|
-
expect(command).to match %r{-r .*/lib/guard/rspec/formatters/focuser.rb -f Guard::RSpec::Formatters::Focuser}
|
19
|
+
it "sets formatter" do
|
20
|
+
expect(command).to match %r{-r .*/lib/guard/rspec/formatter.rb -f Guard::RSpec::Formatter}
|
25
21
|
end
|
26
22
|
|
27
23
|
context "with custom cmd" do
|
@@ -10,13 +10,13 @@ describe Guard::RSpec::Deprecator do
|
|
10
10
|
it "shows warning if SPEC_OPTS is set" do
|
11
11
|
ENV['SPEC_OPTS'] = '-f p'
|
12
12
|
expect(Guard::UI).to receive(:warning).with(
|
13
|
-
'The SPEC_OPTS environment variable is present. This can conflict with guard-rspec
|
13
|
+
'The SPEC_OPTS environment variable is present. This can conflict with guard-rspec.')
|
14
14
|
deprecator.warns_about_deprecated_options
|
15
15
|
ENV['SPEC_OPTS'] = nil # otherwise other specs pick it up and fail
|
16
16
|
end
|
17
17
|
it "does not show warning if SPEC_OPTS is unset" do
|
18
18
|
expect(Guard::UI).to_not receive(:warning).with(
|
19
|
-
'The SPEC_OPTS environment variable is present. This can conflict with guard-rspec
|
19
|
+
'The SPEC_OPTS environment variable is present. This can conflict with guard-rspec.')
|
20
20
|
deprecator.warns_about_deprecated_options
|
21
21
|
end
|
22
22
|
end
|
@@ -53,5 +53,24 @@ describe Guard::RSpec::Deprecator do
|
|
53
53
|
end
|
54
54
|
end
|
55
55
|
|
56
|
+
describe 'with keep_failed option' do
|
57
|
+
let(:options) { { keep_failed: true } }
|
58
|
+
|
59
|
+
it 'shows deprecation warning' do
|
60
|
+
expect(Guard::UI).to receive(:warning).with(
|
61
|
+
'Guard::RSpec DEPRECATION WARNING: The :keep_failed option is deprecated. Please set new :failed_mode option value to :keep instead. https://github.com/guard/guard-rspec#list-of-available-options')
|
62
|
+
deprecator.warns_about_deprecated_options
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
describe 'with focus_on_failed option' do
|
67
|
+
let(:options) { { focus_on_failed: true } }
|
68
|
+
|
69
|
+
it 'shows deprecation warning' do
|
70
|
+
expect(Guard::UI).to receive(:warning).with(
|
71
|
+
'Guard::RSpec DEPRECATION WARNING: The :focus_on_failed option is deprecated. Focus mode is the default and can be changed using new :failed_mode option. https://github.com/guard/guard-rspec#list-of-available-options')
|
72
|
+
deprecator.warns_about_deprecated_options
|
73
|
+
end
|
74
|
+
end
|
56
75
|
end
|
57
76
|
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
require 'spec_helper.rb'
|
2
|
+
|
3
|
+
require 'guard/rspec/formatter'
|
4
|
+
|
5
|
+
describe Guard::RSpec::Formatter do
|
6
|
+
let(:formatter) { Guard::RSpec::Formatter.new(StringIO.new) }
|
7
|
+
|
8
|
+
describe '#dump_summary' do
|
9
|
+
after { File.delete('./tmp/rspec_guard_result') }
|
10
|
+
|
11
|
+
context 'with failures' do
|
12
|
+
let(:example) { double(
|
13
|
+
execution_result: { status: 'failed' },
|
14
|
+
metadata: { location: 'failed_location' }
|
15
|
+
) }
|
16
|
+
|
17
|
+
it 'writes summary line and failed location in tmp dir' do
|
18
|
+
formatter.stub(:examples) { [example] }
|
19
|
+
formatter.dump_summary(123, 3, 1, 0)
|
20
|
+
result = File.open('./tmp/rspec_guard_result').read
|
21
|
+
expect(result).to match /^3 examples, 1 failures in 123\.0 seconds\nfailed_location\n$/
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
context 'with only success' do
|
26
|
+
it 'notifies success' do
|
27
|
+
formatter.dump_summary(123, 3, 0, 0)
|
28
|
+
result = File.open('./tmp/rspec_guard_result').read
|
29
|
+
expect(result).to match /^3 examples, 0 failures in 123\.0 seconds\n$/
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
context 'with pending' do
|
34
|
+
it "notifies pending too" do
|
35
|
+
formatter.dump_summary(123, 3, 0, 1)
|
36
|
+
result = File.open('./tmp/rspec_guard_result').read
|
37
|
+
expect(result).to match /^3 examples, 0 failures \(1 pending\) in 123\.0 seconds\n$/
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Guard::RSpec::Inspectors::BaseInspector do
|
4
|
+
let(:options) { { custom: 'value', spec_paths: %w[myspec] } }
|
5
|
+
let(:inspector) { Guard::RSpec::Inspectors::BaseInspector.new(options) }
|
6
|
+
let(:paths) { %w[spec/foo_spec.rb spec/bar_spec.rb] }
|
7
|
+
let(:abstract_error) { 'Must be implemented in subclass' }
|
8
|
+
|
9
|
+
describe '.initialize' do
|
10
|
+
it 'sets options and spec_paths' do
|
11
|
+
expect(inspector.options).to include(:custom, :spec_paths)
|
12
|
+
expect(inspector.options[:custom]).to eq('value')
|
13
|
+
expect(inspector.spec_paths).to eq(%w[myspec])
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
describe '#paths' do
|
18
|
+
it 'should not be emplemented here' do
|
19
|
+
expect { inspector.paths(paths) }.to raise_error(abstract_error)
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
describe '#failed' do
|
24
|
+
it 'should not be emplemented here' do
|
25
|
+
expect { inspector.failed(paths) }.to raise_error(abstract_error)
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
describe '#reload' do
|
30
|
+
it 'should not be emplemented here' do
|
31
|
+
expect { inspector.reload }.to raise_error(abstract_error)
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Guard::RSpec::Inspectors::Factory do
|
4
|
+
let(:factory) { Guard::RSpec::Inspectors::Factory }
|
5
|
+
let(:options) { {} }
|
6
|
+
|
7
|
+
it 'can not be instantiated' do
|
8
|
+
expect { factory.new(options) }.to raise_error(NoMethodError)
|
9
|
+
end
|
10
|
+
|
11
|
+
context 'with :focus failed mode and custom options' do
|
12
|
+
let(:options) { { failed_mode: :focus, custom: 'value' } }
|
13
|
+
|
14
|
+
it 'creates FocusedInspector instance with custom options' do
|
15
|
+
inspector = factory.create(options)
|
16
|
+
expect(inspector).to be_an_instance_of(Guard::RSpec::Inspectors::FocusedInspector)
|
17
|
+
expect(inspector.options).to eq(options)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
context 'with :keep failed mode and custom options' do
|
22
|
+
let(:options) { { failed_mode: :keep, custom: 'value' } }
|
23
|
+
|
24
|
+
it 'creates KeepingInspector instance with custom options' do
|
25
|
+
inspector = factory.create(options)
|
26
|
+
expect(inspector).to be_an_instance_of(Guard::RSpec::Inspectors::KeepingInspector)
|
27
|
+
expect(inspector.options).to eq(options)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
context 'with :none failed mode and custom options' do
|
32
|
+
let(:options) { { failed_mode: :none, custom: 'value' } }
|
33
|
+
|
34
|
+
it 'creates SimpleInspector instance with custom options' do
|
35
|
+
inspector = factory.create(options)
|
36
|
+
expect(inspector).to be_an_instance_of(Guard::RSpec::Inspectors::SimpleInspector)
|
37
|
+
expect(inspector.options).to eq(options)
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
@@ -0,0 +1,74 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'lib/guard/rspec/inspectors/shared_examples'
|
3
|
+
|
4
|
+
klass = Guard::RSpec::Inspectors::FocusedInspector
|
5
|
+
|
6
|
+
describe klass do
|
7
|
+
include_examples 'inspector', klass
|
8
|
+
|
9
|
+
# Use real paths because BaseInspector#_clean will be used to clean them
|
10
|
+
let(:other_paths) { [
|
11
|
+
'spec/lib/guard/rspec/inspectors/simple_inspector_spec.rb',
|
12
|
+
'spec/lib/guard/rspec/runner_spec.rb'
|
13
|
+
] }
|
14
|
+
let(:other_failed_locations) { %w[./spec/lib/guard/rspec/deprecator_spec.rb:446] }
|
15
|
+
|
16
|
+
it 'remembers failed paths and returns them until they all pass' do
|
17
|
+
expect(inspector.paths(paths)).to match_array(paths)
|
18
|
+
inspector.failed(failed_locations)
|
19
|
+
|
20
|
+
# Return failed_locations until they pass
|
21
|
+
3.times do
|
22
|
+
expect(inspector.paths(other_paths)).to match_array(failed_locations)
|
23
|
+
inspector.failed(other_failed_locations)
|
24
|
+
|
25
|
+
expect(inspector.paths(paths)).to match_array(failed_locations)
|
26
|
+
inspector.failed(other_failed_locations)
|
27
|
+
|
28
|
+
expect(inspector.paths([])).to match_array(failed_locations)
|
29
|
+
inspector.failed(failed_locations)
|
30
|
+
end
|
31
|
+
|
32
|
+
# Now all pass
|
33
|
+
expect(inspector.paths(paths)).to match_array(failed_locations)
|
34
|
+
inspector.failed([])
|
35
|
+
|
36
|
+
# And some fails again
|
37
|
+
expect(inspector.paths(other_paths)).to match_array(other_paths)
|
38
|
+
inspector.failed(other_failed_locations)
|
39
|
+
|
40
|
+
# Return other_failed_locations until they pass
|
41
|
+
3.times do
|
42
|
+
expect(inspector.paths(other_paths)).to match_array(other_failed_locations)
|
43
|
+
inspector.failed(other_failed_locations)
|
44
|
+
|
45
|
+
expect(inspector.paths(paths)).to match_array(other_failed_locations)
|
46
|
+
inspector.failed(other_failed_locations)
|
47
|
+
|
48
|
+
expect(inspector.paths([])).to match_array(other_failed_locations)
|
49
|
+
inspector.failed(failed_locations)
|
50
|
+
end
|
51
|
+
|
52
|
+
# Now all pass
|
53
|
+
expect(inspector.paths(paths)).to match_array(other_failed_locations)
|
54
|
+
inspector.failed([])
|
55
|
+
|
56
|
+
expect(inspector.paths(paths)).to match_array(paths)
|
57
|
+
inspector.failed([])
|
58
|
+
|
59
|
+
expect(inspector.paths(other_paths)).to match_array(other_paths)
|
60
|
+
inspector.failed([])
|
61
|
+
|
62
|
+
expect(inspector.paths([])).to eq([])
|
63
|
+
end
|
64
|
+
|
65
|
+
describe '#reload' do
|
66
|
+
it 'force to forget about focused locations' do
|
67
|
+
expect(inspector.paths(paths)).to match_array(paths)
|
68
|
+
inspector.failed(failed_locations)
|
69
|
+
|
70
|
+
inspector.reload
|
71
|
+
expect(inspector.paths(other_paths)).to match_array(other_paths)
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|