guard-rspec 2.1.0 → 4.7.3

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.
Files changed (57) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +10 -0
  3. data/.hound.yml +3 -0
  4. data/.rspec +2 -0
  5. data/.rubocop.yml +5 -0
  6. data/.rubocop_todo.yml +40 -0
  7. data/.travis.yml +14 -0
  8. data/CONTRIBUTING.md +38 -0
  9. data/Gemfile +25 -0
  10. data/Guardfile +28 -0
  11. data/{LICENSE → LICENSE.txt} +4 -2
  12. data/README.md +99 -114
  13. data/Rakefile +38 -0
  14. data/gemfiles/Gemfile.rspec-2.99 +6 -0
  15. data/gemfiles/Gemfile.rspec-3.4 +6 -0
  16. data/gemfiles/common +9 -0
  17. data/guard-rspec.gemspec +25 -0
  18. data/lib/guard/rspec/command.rb +71 -0
  19. data/lib/guard/rspec/deprecator.rb +86 -0
  20. data/lib/guard/rspec/dsl.rb +72 -0
  21. data/lib/guard/rspec/inspectors/base_inspector.rb +73 -0
  22. data/lib/guard/rspec/inspectors/factory.rb +23 -0
  23. data/lib/guard/rspec/inspectors/focused_inspector.rb +39 -0
  24. data/lib/guard/rspec/inspectors/keeping_inspector.rb +97 -0
  25. data/lib/guard/rspec/inspectors/simple_inspector.rb +21 -0
  26. data/lib/guard/rspec/notifier.rb +55 -0
  27. data/lib/guard/rspec/options.rb +37 -0
  28. data/lib/guard/rspec/results.rb +23 -0
  29. data/lib/guard/rspec/rspec_process.rb +93 -0
  30. data/lib/guard/rspec/runner.rb +71 -174
  31. data/lib/guard/rspec/templates/Guardfile +49 -17
  32. data/lib/guard/rspec/version.rb +1 -1
  33. data/lib/guard/rspec.rb +30 -59
  34. data/lib/guard/rspec_defaults.rb +5 -0
  35. data/lib/guard/rspec_formatter.rb +147 -0
  36. data/lib/guard/rspec_formatter_results_path.rb +29 -0
  37. data/spec/acceptance/fixtures/succeeding_spec.rb +4 -0
  38. data/spec/acceptance/formatter_spec.rb +46 -0
  39. data/spec/lib/guard/rspec/command_spec.rb +95 -0
  40. data/spec/lib/guard/rspec/deprecator_spec.rb +101 -0
  41. data/spec/lib/guard/rspec/inspectors/base_inspector_spec.rb +144 -0
  42. data/spec/lib/guard/rspec/inspectors/factory_spec.rb +45 -0
  43. data/spec/lib/guard/rspec/inspectors/focused_inspector_spec.rb +140 -0
  44. data/spec/lib/guard/rspec/inspectors/keeping_inspector_spec.rb +200 -0
  45. data/spec/lib/guard/rspec/inspectors/shared_examples.rb +121 -0
  46. data/spec/lib/guard/rspec/inspectors/simple_inspector_spec.rb +59 -0
  47. data/spec/lib/guard/rspec/notifier_spec.rb +90 -0
  48. data/spec/lib/guard/rspec/results_spec.rb +66 -0
  49. data/spec/lib/guard/rspec/rspec_process_spec.rb +152 -0
  50. data/spec/lib/guard/rspec/runner_spec.rb +372 -0
  51. data/spec/lib/guard/rspec/template_spec.rb +78 -0
  52. data/spec/lib/guard/rspec_formatter_spec.rb +277 -0
  53. data/spec/lib/guard/rspec_spec.rb +91 -0
  54. data/spec/spec_helper.rb +145 -0
  55. metadata +103 -42
  56. data/lib/guard/rspec/formatter.rb +0 -56
  57. data/lib/guard/rspec/inspector.rb +0 -72
@@ -0,0 +1,277 @@
1
+ require "guard/rspec_formatter"
2
+
3
+ RSpec.describe Guard::RSpecFormatter do
4
+ describe "#dump_summary" do
5
+ def rspec_summary_args(*args)
6
+ return args unless ::RSpec::Core::Version::STRING.start_with?("3.")
7
+
8
+ n = Struct.new(:duration, :example_count, :failure_count, :pending_count)
9
+ [n.new(*args)]
10
+ end
11
+
12
+ let(:example_dump_summary_args) { rspec_summary_args(123, 3, 1, 0) }
13
+ let(:summary_with_no_failures) { rspec_summary_args(123, 3, 0, 0) }
14
+ let(:summary_with_only_pending) { rspec_summary_args(123, 3, 0, 1) }
15
+
16
+ let(:failed_example) do
17
+ result =
18
+ if ::RSpec::Core::Version::STRING.start_with?("3.")
19
+ double(status: "failed")
20
+ else
21
+ { status: "failed" }
22
+ end
23
+
24
+ double(execution_result: result, metadata: { location: spec_filename })
25
+ end
26
+
27
+ let(:writer) do
28
+ StringIO.new
29
+ end
30
+
31
+ let(:stub_formatter) { true }
32
+
33
+ let(:formatter) do
34
+ described_class.new(StringIO.new).tap do |formatter_stub|
35
+ if stub_formatter
36
+ allow(formatter_stub).to receive(:_write) do |&block|
37
+ block.call writer
38
+ end
39
+ end
40
+ end
41
+ end
42
+
43
+ let(:result) do
44
+ writer.rewind
45
+ writer.read
46
+ end
47
+
48
+ context "without stubbed IO" do
49
+ let(:stub_formatter) { false }
50
+
51
+ around do |example|
52
+ env_var = "GUARD_RSPEC_RESULTS_FILE"
53
+ old = ENV[env_var]
54
+ ENV[env_var] = "foobar.txt"
55
+ example.run
56
+ ENV[env_var] = old
57
+ end
58
+
59
+ it "creates temporary file and and writes to it" do
60
+ file = File.expand_path("foobar.txt")
61
+
62
+ expect(FileUtils).to receive(:mkdir_p).
63
+ with(File.dirname(file)) {}
64
+
65
+ expect(File).to receive(:open).
66
+ with(file, "w") do |_, _, &block|
67
+ block.call writer
68
+ end
69
+
70
+ formatter.dump_summary(*example_dump_summary_args)
71
+ end
72
+
73
+ context "when writing file fails" do
74
+ it "outputs an error" do
75
+ allow(FileUtils).to receive(:mkdir_p).and_raise(Errno::EACCES)
76
+ expect do
77
+ formatter.dump_summary(*example_dump_summary_args)
78
+ end.to raise_error(Errno::EACCES)
79
+ end
80
+ end
81
+
82
+ context "when writer fails" do
83
+ it "outputs an error" do
84
+ allow(FileUtils).to receive(:mkdir_p).and_raise(TypeError, "foo")
85
+ expect do
86
+ formatter.dump_summary(*example_dump_summary_args)
87
+ end.to raise_error(TypeError, "foo")
88
+ end
89
+ end
90
+
91
+ context "when no env is passed" do
92
+ let(:file) { File.join(Dir.pwd, "tmp/rspec_guard_result") }
93
+
94
+ before do
95
+ ENV["GUARD_RSPEC_RESULTS_FILE"] = nil
96
+
97
+ allow(FileUtils).to receive(:mkdir_p).
98
+ with(File.dirname(file)) {}
99
+
100
+ allow(File).to receive(:open).
101
+ with(file, "w") do |_, _, &block|
102
+ block.call writer
103
+ end
104
+
105
+ allow(STDERR).to receive(:puts).with(/no environment/)
106
+ end
107
+
108
+ it "warns" do
109
+ expect(STDERR).to receive(:puts).with(/no environment/)
110
+ formatter.dump_summary(*example_dump_summary_args)
111
+ end
112
+
113
+ it "uses default file" do
114
+ expect(File).to receive(:open).
115
+ with(file, "w") do |_, _, &block|
116
+ block.call writer
117
+ end
118
+ formatter.dump_summary(*example_dump_summary_args)
119
+ end
120
+ end
121
+ end
122
+
123
+ context "with failures" do
124
+ let(:spec_filename) { "failed_location_spec.rb" }
125
+
126
+ def expected_output(spec_filename)
127
+ /^3 examples, 1 failures in 123\.0 seconds\n#{spec_filename}\n$/
128
+ end
129
+
130
+ it "writes summary line and failed location in tmp dir" do
131
+ allow(formatter).to receive(:examples) { [failed_example] }
132
+ formatter.dump_summary(*example_dump_summary_args)
133
+ expect(result).to match expected_output(spec_filename)
134
+ end
135
+
136
+ it "writes only uniq filenames out" do
137
+ allow(formatter).to receive(:examples).
138
+ and_return([failed_example, failed_example])
139
+
140
+ formatter.dump_summary(*example_dump_summary_args)
141
+ expect(result).to match expected_output(spec_filename)
142
+ end
143
+
144
+ let(:notification) { example_dump_summary_args }
145
+
146
+ it "writes summary line and failed location" do
147
+ allow(formatter).to receive(:examples) { [failed_example] }
148
+ formatter.dump_summary(*notification)
149
+ expect(result).to match expected_output(spec_filename)
150
+ end
151
+ end
152
+
153
+ it "should find the spec file for shared examples" do
154
+ metadata = {
155
+ location: "./spec/support/breadcrumbs.rb:75",
156
+ example_group: { location: "./spec/requests/breadcrumbs_spec.rb:218" }
157
+ }
158
+
159
+ result = described_class.extract_spec_location(metadata)
160
+ expect(result).to start_with "./spec/requests/breadcrumbs_spec.rb"
161
+ end
162
+
163
+ # Skip location because of rspec issue
164
+ # https://github.com/rspec/rspec-core/issues/1243
165
+ it "returns only the spec file without line number for shared examples" do
166
+ metadata = {
167
+ location: "./spec/support/breadcrumbs.rb:75",
168
+ example_group: { location: "./spec/requests/breadcrumbs_spec.rb:218" }
169
+ }
170
+ expect(described_class.extract_spec_location(metadata)).
171
+ to eq "./spec/requests/breadcrumbs_spec.rb"
172
+ end
173
+
174
+ context "when a shared examples has no location" do
175
+ it "should return location of the root spec" do
176
+ metadata = {
177
+ location: "./spec/support/breadcrumbs.rb:75",
178
+ example_group: {}
179
+ }
180
+
181
+ expect(STDERR).to receive(:puts).
182
+ with("no spec file location in #{metadata.inspect}")
183
+
184
+ expect(described_class.extract_spec_location(metadata)).
185
+ to eq metadata[:location]
186
+ end
187
+ end
188
+
189
+ context "when a shared examples are nested" do
190
+ it "should return location of the root spec" do
191
+ metadata = {
192
+ location: "./spec/support/breadcrumbs.rb:75",
193
+ example_group: {
194
+ example_group: {
195
+ location: "./spec/requests/breadcrumbs_spec.rb:218"
196
+ }
197
+ }
198
+ }
199
+
200
+ expect(described_class.extract_spec_location(metadata)).
201
+ to eq "./spec/requests/breadcrumbs_spec.rb"
202
+ end
203
+ end
204
+
205
+ context "when RSpec 3.0 metadata is present" do
206
+ it "should return location of the root spec" do
207
+ metadata = {
208
+ location: "./spec/support/breadcrumbs.rb:75",
209
+ parent_example_group: {
210
+ location: "./spec/requests/breadcrumbs_spec.rb:218"
211
+ }
212
+ }
213
+
214
+ expect(described_class.extract_spec_location(metadata)).
215
+ to eq "./spec/requests/breadcrumbs_spec.rb"
216
+ end
217
+ end
218
+
219
+ context "with only success" do
220
+ it "notifies success" do
221
+ formatter.dump_summary(*summary_with_no_failures)
222
+ expect(result).to match(/^3 examples, 0 failures in 123\.0 seconds\n$/)
223
+ end
224
+ end
225
+
226
+ context "with pending" do
227
+ it "notifies pending too" do
228
+ formatter.dump_summary(*summary_with_only_pending)
229
+ expect(result).to match(
230
+ /^3 examples, 0 failures \(1 pending\) in 123\.0 seconds\n$/
231
+ )
232
+ end
233
+ end
234
+
235
+ context "when RSpec 3.0 uses ext globs" do
236
+ before do
237
+ allow(::RSpec.configuration).to receive(:pattern).
238
+ and_return("**{,/*/**}/*_spec.rb")
239
+ end
240
+
241
+ context "when Ruby does not support ext glob matcher" do
242
+ before do
243
+ allow(File).to receive(:const_defined?).with(:FNM_EXTGLOB) { false }
244
+ end
245
+
246
+ let(:metadata) { { location: "./spec/foo_spec.rb:75" } }
247
+
248
+ it "fails" do
249
+ expect do
250
+ described_class.extract_spec_location(metadata)
251
+ end.to raise_error(
252
+ described_class::Error::UnsupportedPattern,
253
+ "Your RSpec.configuration.pattern uses characters unsupported "\
254
+ "by your Ruby version (File::FNM_EXTGLOB is undefined)"
255
+ )
256
+ end
257
+ end
258
+ end
259
+
260
+ context "when RSpec 3.0 is configured to use multiple patterns" do
261
+ before do
262
+ allow(::RSpec.configuration).to receive(:pattern).
263
+ and_return("**{,/*/**}/*_spec.rb,**/*.feature")
264
+ end
265
+
266
+ it "matches a spec file with the first pattern" do
267
+ expect(described_class.spec_path?("./spec/foo_spec.rb")).
268
+ to be_truthy
269
+ end
270
+
271
+ it "matches a spec file with the second pattern" do
272
+ expect(described_class.spec_path?("./spec/acceptance/bar.feature")).
273
+ to be_truthy
274
+ end
275
+ end
276
+ end
277
+ end
@@ -0,0 +1,91 @@
1
+ require "guard/compat/test/helper"
2
+ require "guard/rspec"
3
+
4
+ RSpec.describe Guard::RSpec do
5
+ let(:default_options) { Guard::RSpec::Options::DEFAULTS }
6
+ let(:options) { {} }
7
+ let(:plugin) { Guard::RSpec.new(options) }
8
+ let(:runner) { instance_double(Guard::RSpec::Runner) }
9
+
10
+ before do
11
+ allow(Guard::Compat::UI).to receive(:info)
12
+ allow(Guard::RSpec::Deprecator).to receive(:warns_about_deprecated_options)
13
+ allow(Guard::RSpec::Runner).to receive(:new) { runner }
14
+ end
15
+
16
+ describe ".initialize" do
17
+ it "instanciates with default and custom options" do
18
+ guard_rspec = Guard::RSpec.new(foo: :bar)
19
+ expect(guard_rspec.options).to eq(default_options.merge(foo: :bar))
20
+ end
21
+
22
+ it "instanciates Runner with all default and custom options" do
23
+ expect(Guard::RSpec::Runner).to receive(:new).
24
+ with(default_options.merge(foo: :bar))
25
+ Guard::RSpec.new(foo: :bar)
26
+ end
27
+
28
+ it "warns deprecated options" do
29
+ expect(Guard::RSpec::Deprecator).
30
+ to receive(:warns_about_deprecated_options).
31
+ with(default_options.merge(foo: :bar))
32
+
33
+ Guard::RSpec.new(foo: :bar)
34
+ end
35
+ end
36
+
37
+ describe "#start" do
38
+ it "doesn't call #run_all by default" do
39
+ expect(plugin).to_not receive(:run_all)
40
+ plugin.start
41
+ end
42
+
43
+ context "with all_on_start at true" do
44
+ let(:options) { { all_on_start: true } }
45
+
46
+ it "calls #run_all" do
47
+ expect(plugin).to receive(:run_all)
48
+ plugin.start
49
+ end
50
+ end
51
+ end
52
+
53
+ describe "#run_all" do
54
+ it "runs all specs via runner" do
55
+ expect(runner).to receive(:run_all) { true }
56
+ plugin.run_all
57
+ end
58
+
59
+ it "throws task_has_failed if runner return false" do
60
+ allow(runner).to receive(:run_all) { false }
61
+ expect(plugin).to receive(:throw).with(:task_has_failed)
62
+ plugin.run_all
63
+ end
64
+ end
65
+
66
+ describe "#reload" do
67
+ it "reloads via runner" do
68
+ expect(runner).to receive(:reload)
69
+ plugin.reload
70
+ end
71
+ end
72
+
73
+ describe "#run_on_modifications" do
74
+ let(:paths) { %w(path1 path2) }
75
+ it "runs all specs via runner" do
76
+ expect(runner).to receive(:run).with(paths) { true }
77
+ plugin.run_on_modifications(paths)
78
+ end
79
+
80
+ it "does nothing if paths empty" do
81
+ expect(runner).to_not receive(:run)
82
+ plugin.run_on_modifications([])
83
+ end
84
+
85
+ it "throws task_has_failed if runner return false" do
86
+ allow(runner).to receive(:run) { false }
87
+ expect(plugin).to receive(:throw).with(:task_has_failed)
88
+ plugin.run_on_modifications(paths)
89
+ end
90
+ end
91
+ end
@@ -0,0 +1,145 @@
1
+ require "rspec"
2
+
3
+ # To help produce better bug reports in Rubinius
4
+ if RUBY_ENGINE == "rbx"
5
+ $DEBUG = true # would be nice if this didn't fail ... :(
6
+ require "rspec/matchers"
7
+ require "rspec/matchers/built_in/be"
8
+ end
9
+
10
+ if ENV["CI"]
11
+ require "coveralls"
12
+ Coveralls.wear!
13
+ end
14
+
15
+ rspec_version = ::RSpec::Version::STRING.to_f
16
+ old_rspec = (rspec_version < 3)
17
+
18
+ if old_rspec
19
+ module RSpec
20
+ module Core
21
+ class ExampleGroup
22
+ def instance_double(*args)
23
+ double(*args)
24
+ end
25
+ end
26
+ end
27
+ end
28
+ end
29
+
30
+ # See http://rubydoc.info/gems/rspec-core/RSpec/Core/Configuration
31
+ RSpec.configure do |config|
32
+ config.register_ordering :global do |examples|
33
+ examples.partition { |ex| ex.metadata[:type] != :acceptance }.flatten(1)
34
+ end
35
+
36
+ # Use global for running acceptance tests last
37
+ config.order = :global
38
+
39
+ config.expect_with :rspec do |expectations|
40
+ # This option will default to `true` in RSpec 4. It makes the `description`
41
+ # and `failure_message` of custom matchers include text for helper methods
42
+ # defined using `chain`, e.g.:
43
+ # be_bigger_than(2).and_smaller_than(4).description
44
+ # # => "be bigger than 2 and smaller than 4"
45
+ # ...rather than:
46
+ # # => "be bigger than 2"
47
+
48
+ unless old_rspec
49
+ if rspec_version > 3.0
50
+ expectations.include_chain_clauses_in_custom_matcher_descriptions = true
51
+ end
52
+ end
53
+ end
54
+
55
+ # rspec-mocks config goes here. You can use an alternate test double
56
+ # library (such as bogus or mocha) by changing the `mock_with` option here.
57
+ config.mock_with :rspec do |mocks|
58
+ # Prevents you from mocking or stubbing a method that does not exist on
59
+ # a real object. This is generally recommended, and will default to
60
+ # `true` in RSpec 4.
61
+ mocks.verify_partial_doubles = true unless old_rspec
62
+ end
63
+
64
+ # These two settings work together to allow you to limit a spec run
65
+ # to individual examples or groups you care about by tagging them with
66
+ # `:focus` metadata. When nothing is tagged with `:focus`, all examples
67
+ # get run.
68
+ config.filter_run focus: ENV["CI"] != "true"
69
+ config.run_all_when_everything_filtered = true
70
+
71
+ # Limits the available syntax to the non-monkey patched syntax that is
72
+ # recommended.
73
+ # For more details, see:
74
+ # - http://myronmars.to/n/dev-blog/2012/06/rspecs-new-expectation-syntax
75
+ # - http://teaisaweso.me/blog/2013/05/27/rspecs-new-message-expectation-syntax/
76
+ # - http://myronmars.to/n/dev-blog/2014/05/notable-changes-in-rspec-3#new__config_option_to_disable_rspeccore_monkey_patching
77
+
78
+ config.disable_monkey_patching! unless old_rspec
79
+
80
+ # This setting enables warnings. It's recommended, but in some cases may
81
+ # be too noisy due to issues in dependencies.
82
+ # config.warnings = true
83
+
84
+ # Many RSpec users commonly either run the entire suite or an individual
85
+ # file, and it's useful to allow more verbose output when running an
86
+ # individual spec file.
87
+ if config.files_to_run.one?
88
+ # Use the documentation formatter for detailed output,
89
+ # unless a formatter has already been configured
90
+ # (e.g. via a command-line flag).
91
+ config.default_formatter = "doc"
92
+ end
93
+
94
+ # Print the 10 slowest examples and example groups at the
95
+ # end of the spec run, to help surface which specs are running
96
+ # particularly slow.
97
+ # config.profile_examples = 10
98
+
99
+ # Seed global randomization in this process using the `--seed` CLI option.
100
+ # Setting this allows you to use `--seed` to deterministically reproduce
101
+ # test failures related to randomization by passing the same `--seed` value
102
+ # as the one that triggered the failure.
103
+ Kernel.srand config.seed
104
+
105
+ config.raise_errors_for_deprecations!
106
+
107
+ config.before do
108
+ %w(exist?).each do |meth|
109
+ allow(Dir).to receive(meth.to_sym) do |*args|
110
+ abort "stub me: Dir.#{meth}(#{args.map(&:inspect) * ','})!"
111
+ end
112
+ end
113
+
114
+ allow(Dir).to receive(:[]) do |*args|
115
+ abort "stub me: Dir[#{args.first}]!"
116
+ end
117
+
118
+ unless RUBY_ENGINE == "rbx"
119
+ # RBX uses cache in ~/.rbx
120
+ %w(directory?).each do |meth|
121
+ allow(File).to receive(meth.to_sym) do |*args|
122
+ abort "stub me: File.#{meth}(#{args.map(&:inspect) * ','})!"
123
+ end
124
+ end
125
+ end
126
+
127
+ %w(delete readlines).each do |meth|
128
+ allow(File).to receive(meth.to_sym) do |*args|
129
+ abort "stub me: File.#{meth}(#{args.map(&:inspect) * ','})!"
130
+ end
131
+ end
132
+
133
+ %w(mkdir mkdir_p).each do |meth|
134
+ allow(FileUtils).to receive(meth.to_sym) do |*args|
135
+ abort "stub me: FileUtils.#{meth}(#{args.map(&:inspect) * ','})!"
136
+ end
137
+ end
138
+
139
+ %w(spawn system).each do |meth|
140
+ allow(Kernel).to receive(meth.to_sym) do |*args|
141
+ abort "stub me: Kernel.#{meth}(#{args.map(&:inspect) * ','})!"
142
+ end
143
+ end
144
+ end
145
+ end