knapsack_pro 6.0.4 → 7.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (42) hide show
  1. checksums.yaml +4 -4
  2. data/.circleci/config.yml +80 -19
  3. data/.github/pull_request_template.md +22 -0
  4. data/.gitignore +4 -0
  5. data/CHANGELOG.md +95 -0
  6. data/Gemfile +9 -0
  7. data/README.md +7 -9
  8. data/knapsack_pro.gemspec +2 -1
  9. data/lib/knapsack_pro/adapters/base_adapter.rb +7 -2
  10. data/lib/knapsack_pro/adapters/cucumber_adapter.rb +1 -3
  11. data/lib/knapsack_pro/adapters/rspec_adapter.rb +24 -9
  12. data/lib/knapsack_pro/config/env.rb +1 -9
  13. data/lib/knapsack_pro/extensions/rspec_extension.rb +137 -0
  14. data/lib/knapsack_pro/formatters/time_tracker.rb +10 -26
  15. data/lib/knapsack_pro/formatters/time_tracker_fetcher.rb +6 -0
  16. data/lib/knapsack_pro/presenter.rb +1 -1
  17. data/lib/knapsack_pro/pure/queue/rspec_pure.rb +100 -0
  18. data/lib/knapsack_pro/runners/queue/base_runner.rb +6 -1
  19. data/lib/knapsack_pro/runners/queue/cucumber_runner.rb +6 -6
  20. data/lib/knapsack_pro/runners/queue/minitest_runner.rb +6 -6
  21. data/lib/knapsack_pro/runners/queue/rspec_runner.rb +127 -173
  22. data/lib/knapsack_pro/urls.rb +2 -0
  23. data/lib/knapsack_pro/version.rb +1 -1
  24. data/lib/knapsack_pro.rb +1 -0
  25. data/spec/integration/runners/queue/rspec_runner.rb +80 -0
  26. data/spec/integration/runners/queue/rspec_runner_spec.rb +2405 -0
  27. data/spec/knapsack_pro/adapters/base_adapter_spec.rb +17 -11
  28. data/spec/knapsack_pro/adapters/cucumber_adapter_spec.rb +2 -5
  29. data/spec/knapsack_pro/adapters/rspec_adapter_spec.rb +56 -24
  30. data/spec/knapsack_pro/config/env_spec.rb +1 -35
  31. data/spec/knapsack_pro/formatters/time_tracker_fetcher_spec.rb +30 -0
  32. data/spec/knapsack_pro/formatters/time_tracker_specs.rb +8 -37
  33. data/spec/knapsack_pro/hooks/queue_spec.rb +2 -2
  34. data/spec/knapsack_pro/presenter_spec.rb +1 -1
  35. data/spec/knapsack_pro/pure/queue/rspec_pure_spec.rb +248 -0
  36. data/spec/knapsack_pro/runners/queue/cucumber_runner_spec.rb +16 -16
  37. data/spec/knapsack_pro/runners/queue/minitest_runner_spec.rb +14 -14
  38. data/spec/knapsack_pro_spec.rb +3 -3
  39. metadata +19 -12
  40. data/lib/knapsack_pro/formatters/rspec_queue_profile_formatter_extension.rb +0 -58
  41. data/lib/knapsack_pro/formatters/rspec_queue_summary_formatter.rb +0 -145
  42. data/spec/knapsack_pro/runners/queue/rspec_runner_spec.rb +0 -536
@@ -159,7 +159,7 @@ describe KnapsackPro::Adapters::BaseAdapter do
159
159
  it do
160
160
  logger = instance_double(Logger)
161
161
  expect(KnapsackPro).to receive(:logger).and_return(logger)
162
- expect(logger).to receive(:debug).with('Test suite time execution recording enabled.')
162
+ expect(logger).to receive(:debug).with('Regular Mode enabled.')
163
163
  end
164
164
  it { expect(subject).to receive(:bind_time_tracker) }
165
165
  it { expect(subject).to receive(:bind_save_report) }
@@ -168,24 +168,22 @@ describe KnapsackPro::Adapters::BaseAdapter do
168
168
  context 'when queue recording enabled' do
169
169
  let(:queue_recording_enabled?) { true }
170
170
 
171
- before do
172
- allow(subject).to receive(:bind_before_queue_hook)
173
- allow(subject).to receive(:bind_time_tracker)
174
- end
175
-
176
- it do
171
+ it 'calls queue hooks in proper order before binding time tracker' do
177
172
  logger = instance_double(Logger)
178
173
  expect(KnapsackPro).to receive(:logger).and_return(logger)
179
- expect(logger).to receive(:debug).with('Test suite time execution queue recording enabled.')
174
+ expect(logger).to receive(:debug).with('Queue Mode enabled.')
175
+
176
+ expect(subject).to receive(:bind_before_queue_hook).ordered
177
+ expect(subject).to receive(:bind_after_queue_hook).ordered
178
+ expect(subject).to receive(:bind_time_tracker).ordered
180
179
  end
181
- it { expect(subject).to receive(:bind_before_queue_hook) }
182
- it { expect(subject).to receive(:bind_time_tracker) }
183
180
  end
184
181
 
185
182
  context 'when recording disabled' do
186
- it { expect(subject).not_to receive(:bind_time_tracker) }
187
183
  it { expect(subject).not_to receive(:bind_save_report) }
188
184
  it { expect(subject).not_to receive(:bind_before_queue_hook) }
185
+ it { expect(subject).not_to receive(:bind_after_queue_hook) }
186
+ it { expect(subject).not_to receive(:bind_time_tracker) }
189
187
  end
190
188
  end
191
189
 
@@ -212,4 +210,12 @@ describe KnapsackPro::Adapters::BaseAdapter do
212
210
  }.to raise_error(NotImplementedError)
213
211
  end
214
212
  end
213
+
214
+ describe '#bind_after_queue_hook' do
215
+ it do
216
+ expect {
217
+ subject.bind_after_queue_hook
218
+ }.to raise_error(NotImplementedError)
219
+ end
220
+ end
215
221
  end
@@ -203,16 +203,13 @@ describe KnapsackPro::Adapters::CucumberAdapter do
203
203
  end
204
204
  end
205
205
 
206
- describe '#bind_queue_mode' do
206
+ describe '#bind_after_queue_hook' do
207
207
  it do
208
- expect(subject).to receive(:bind_before_queue_hook)
209
- expect(subject).to receive(:bind_time_tracker)
210
-
211
208
  expect(::Kernel).to receive(:at_exit).and_yield
212
209
  expect(KnapsackPro::Hooks::Queue).to receive(:call_after_subset_queue)
213
210
  expect(KnapsackPro::Report).to receive(:save_subset_queue_to_file)
214
211
 
215
- subject.bind_queue_mode
212
+ subject.bind_after_queue_hook
216
213
  end
217
214
  end
218
215
  end
@@ -187,6 +187,60 @@ describe KnapsackPro::Adapters::RSpecAdapter do
187
187
  end
188
188
  end
189
189
 
190
+ describe '.has_require_rails_helper_option?' do
191
+ subject { described_class.has_require_rails_helper_option?(cli_args) }
192
+
193
+ context 'when require option is provided as -r' do
194
+ let(:cli_args) { ['-r', 'rails_helper'] }
195
+
196
+ it { expect(subject).to be true }
197
+ end
198
+
199
+ context 'when require option is provided as --require' do
200
+ let(:cli_args) { ['--require', 'rails_helper'] }
201
+
202
+ it { expect(subject).to be true }
203
+ end
204
+
205
+ context 'when require option is provided without delimiter' do
206
+ let(:cli_args) { ['-rrails_helper'] }
207
+
208
+ it { expect(subject).to be true }
209
+ end
210
+
211
+ context 'when require option is not provided' do
212
+ let(:cli_args) { ['--fake', 'value'] }
213
+
214
+ it { expect(subject).to be false }
215
+ end
216
+ end
217
+
218
+ describe '.rails_helper_exists?' do
219
+ subject { described_class.rails_helper_exists?(test_dir) }
220
+
221
+ let(:test_dir) { 'spec_fake' }
222
+
223
+ context 'when rails_helper exists' do
224
+ before do
225
+ File.open("#{test_dir}/rails_helper.rb", 'w')
226
+ end
227
+
228
+ after do
229
+ FileUtils.rm("#{test_dir}/rails_helper.rb")
230
+ end
231
+
232
+ it { expect(subject).to be true }
233
+ end
234
+
235
+ context 'when rails_helper does not exist' do
236
+ before do
237
+ FileUtils.rm_f("#{test_dir}/rails_helper.rb")
238
+ end
239
+
240
+ it { expect(subject).to be false }
241
+ end
242
+ end
243
+
190
244
  describe '.order_option' do
191
245
  subject { described_class.order_option(cli_args) }
192
246
 
@@ -341,24 +395,13 @@ describe KnapsackPro::Adapters::RSpecAdapter do
341
395
  end
342
396
 
343
397
  context 'with no focus' do
344
- let(:logger) { instance_double(Logger) }
345
- let(:duration) { 65 }
346
- let(:global_time) { 'Global time execution for tests: 01m 05s' }
347
- let(:time_tracker) { instance_double(KnapsackPro::Formatters::TimeTracker) }
348
-
349
398
  it 'records time for current test path' do
350
399
  expect(config).to receive(:around).with(:each).and_yield(current_example)
351
- expect(config).to receive(:after).with(:suite).and_yield
352
- expect(::RSpec).to receive(:configure).twice.and_yield(config)
400
+ expect(config).to receive(:append_after).with(:suite)
401
+ expect(::RSpec).to receive(:configure).at_least(1).and_yield(config)
353
402
 
354
403
  expect(current_example).to receive(:run)
355
404
 
356
- expect(time_tracker).to receive(:batch_duration).and_return(duration)
357
- expect(KnapsackPro::Formatters::TimeTrackerFetcher).to receive(:call).and_return(time_tracker)
358
-
359
- expect(KnapsackPro).to receive(:logger).and_return(logger)
360
- expect(logger).to receive(:debug).with(global_time)
361
-
362
405
  subject.bind_time_tracker
363
406
  end
364
407
  end
@@ -378,16 +421,5 @@ describe KnapsackPro::Adapters::RSpecAdapter do
378
421
  subject.bind_save_report
379
422
  end
380
423
  end
381
-
382
- describe '#bind_before_queue_hook' do
383
- it do
384
- expect(config).to receive(:before).with(:suite).and_yield
385
- expect(::RSpec).to receive(:configure).and_yield(config)
386
-
387
- expect(KnapsackPro::Hooks::Queue).to receive(:call_before_queue)
388
-
389
- subject.bind_before_queue_hook
390
- end
391
- end
392
424
  end
393
425
  end
@@ -511,40 +511,6 @@ describe KnapsackPro::Config::Env do
511
511
  end
512
512
  end
513
513
 
514
- describe '.modify_default_rspec_formatters' do
515
- subject { described_class.modify_default_rspec_formatters }
516
-
517
- context 'when ENV exists' do
518
- let(:modify_default_rspec_formatters) { 'false' }
519
- before { stub_const("ENV", { 'KNAPSACK_PRO_MODIFY_DEFAULT_RSPEC_FORMATTERS' => modify_default_rspec_formatters }) }
520
- it { should eq modify_default_rspec_formatters }
521
- end
522
-
523
- context "when ENV doesn't exist" do
524
- it { should be true }
525
- end
526
- end
527
-
528
- describe '.modify_default_rspec_formatters?' do
529
- subject { described_class.modify_default_rspec_formatters? }
530
-
531
- before do
532
- expect(described_class).to receive(:modify_default_rspec_formatters).and_return(modify_default_rspec_formatters)
533
- end
534
-
535
- context 'when enabled' do
536
- let(:modify_default_rspec_formatters) { true }
537
-
538
- it { should be true }
539
- end
540
-
541
- context 'when disabled' do
542
- let(:modify_default_rspec_formatters) { false }
543
-
544
- it { should be false }
545
- end
546
- end
547
-
548
514
  describe '.branch_encrypted' do
549
515
  subject { described_class.branch_encrypted }
550
516
 
@@ -975,7 +941,7 @@ describe KnapsackPro::Config::Env do
975
941
  end
976
942
 
977
943
  context "when ENV doesn't exist" do
978
- it { should eql ::Logger::DEBUG }
944
+ it { should eql ::Logger::INFO }
979
945
  end
980
946
  end
981
947
 
@@ -0,0 +1,30 @@
1
+ require(KnapsackPro.root + '/lib/knapsack_pro/formatters/time_tracker')
2
+
3
+ describe KnapsackPro::Formatters::TimeTrackerFetcher do
4
+ describe '.unexecuted_test_files' do
5
+ subject { described_class.unexecuted_test_files(scheduled_paths) }
6
+
7
+ context 'when the time tracker formatter not found' do
8
+ let(:scheduled_paths) { ['a_spec.rb'] }
9
+
10
+ it do
11
+ expect(subject).to eq []
12
+ end
13
+ end
14
+
15
+ context 'when the time tracker formatter is found' do
16
+ let(:time_tracker) { instance_double(KnapsackPro::Formatters::TimeTracker) }
17
+ let(:scheduled_paths) { ['a_spec.rb', 'b_spec.rb'] }
18
+ let(:unexecuted_test_files) { double(:unexecuted_test_files) }
19
+
20
+ before do
21
+ expect(described_class).to receive(:call).and_return(time_tracker)
22
+ expect(time_tracker).to receive(:unexecuted_test_files).with(scheduled_paths).and_return(unexecuted_test_files)
23
+ end
24
+
25
+ it do
26
+ expect(subject).to eq unexecuted_test_files
27
+ end
28
+ end
29
+ end
30
+ end
@@ -4,6 +4,7 @@
4
4
  require 'rspec/core'
5
5
  require 'knapsack_pro'
6
6
  require 'stringio'
7
+ require 'tempfile'
7
8
  require_relative '../../../lib/knapsack_pro/formatters/time_tracker'
8
9
 
9
10
  class TestTimeTracker
@@ -327,24 +328,6 @@ class TestTimeTracker
327
328
  end
328
329
  end
329
330
 
330
- def test_batch_duration
331
- KnapsackPro::Formatters::TimeTracker.define_method(:rspec_split_by_test_example?) do |_file|
332
- false
333
- end
334
-
335
- spec = <<~SPEC
336
- describe "KnapsackPro::Formatters::TimeTracker" do
337
- it do
338
- expect(1).to eq 1
339
- end
340
- end
341
- SPEC
342
-
343
- run_specs(spec) do |_, _, time_tracker|
344
- raise unless time_tracker.batch_duration > 0.0
345
- end
346
- end
347
-
348
331
  def test_unexecuted_test_files
349
332
  KnapsackPro::Formatters::TimeTracker.define_method(:rspec_split_by_test_example?) do |_file|
350
333
  false
@@ -372,14 +355,6 @@ class TestTimeTracker
372
355
  KnapsackPro::Formatters::TimeTracker.define_method(:rspec_split_by_test_example?) do |_file|
373
356
  false
374
357
  end
375
- KnapsackPro::Formatters::TimeTracker.class_eval do
376
- alias_method :original_stop, :stop
377
-
378
- # In Regular Mode, #subset is called before #stop.
379
- # This test makes #stop a noop to simulate that behavior.
380
- define_method(:stop) do |_|
381
- end
382
- end
383
358
 
384
359
  spec = <<~SPEC
385
360
  describe "KnapsackPro::Formatters::TimeTracker" do
@@ -401,23 +376,20 @@ class TestTimeTracker
401
376
  raise unless files[0]["time_execution"] > 0.10
402
377
  raise unless files[0]["time_execution"] < 0.15
403
378
  end
404
-
405
- ensure
406
- KnapsackPro::Formatters::TimeTracker.class_eval do
407
- undef :stop
408
- alias_method :stop, :original_stop
409
- end
410
379
  end
411
380
 
412
381
  private
413
382
 
414
383
  def run_specs(specs)
415
- paths = Array(specs).map.with_index do |spec, i|
416
- path = "spec/knapsack_pro/formatters/#{i}_#{SecureRandom.uuid}_spec.rb"
417
- File.open(path, 'w') { |file| file.write(spec) }
418
- path
384
+ files = Array(specs).map.with_index do |spec, i|
385
+ file = Tempfile.new(["tmp_time_tracker_#{i}", "_spec.rb"], "./spec/knapsack_pro/formatters/")
386
+ file.write(spec)
387
+ file.rewind
388
+ file
419
389
  end
420
390
 
391
+ paths = files.map(&:path).map { _1.sub("./", "") }
392
+
421
393
  options = ::RSpec::Core::ConfigurationOptions.new([
422
394
  "--format", KnapsackPro::Formatters::TimeTracker.to_s,
423
395
  *paths,
@@ -436,7 +408,6 @@ class TestTimeTracker
436
408
  yield(paths, times, time_tracker)
437
409
 
438
410
  ensure
439
- paths.each { |path| File.delete(path) }
440
411
  # Need to reset because RSpec keeps reusing the same instance.
441
412
  time_tracker.instance_variable_set(:@queue, {}) if time_tracker
442
413
  time_tracker.instance_variable_set(:@started, time_tracker.send(:now)) if time_tracker
@@ -93,8 +93,8 @@ describe KnapsackPro::Hooks::Queue do
93
93
  let(:subset_queue_id) { double }
94
94
 
95
95
  before do
96
- expect(KnapsackPro::Config::Env).to receive(:queue_id).twice.and_return(queue_id)
97
- expect(KnapsackPro::Config::Env).to receive(:subset_queue_id).twice.and_return(subset_queue_id)
96
+ expect(KnapsackPro::Config::Env).to receive(:queue_id).at_least(:once).and_return(queue_id)
97
+ expect(KnapsackPro::Config::Env).to receive(:subset_queue_id).at_least(:once).and_return(subset_queue_id)
98
98
 
99
99
  $expected_called_blocks = []
100
100
 
@@ -8,7 +8,7 @@ describe KnapsackPro::Presenter do
8
8
  expect(KnapsackPro).to receive(:tracker).and_return(tracker)
9
9
  end
10
10
 
11
- it { should eql "Global time execution for tests: 01h 02m 03s" }
11
+ it { should eql "Global test execution duration: 01h 02m 03s" }
12
12
  end
13
13
 
14
14
  describe '.pretty_seconds' do
@@ -0,0 +1,248 @@
1
+ require(KnapsackPro.root + '/lib/knapsack_pro/formatters/time_tracker')
2
+ require(KnapsackPro.root + '/lib/knapsack_pro/extensions/rspec_extension')
3
+
4
+ describe KnapsackPro::Pure::Queue::RSpecPure do
5
+ let(:rspec_pure) { described_class.new }
6
+
7
+ describe '#add_knapsack_pro_formatters_to' do
8
+ subject { rspec_pure.add_knapsack_pro_formatters_to(spec_opts) }
9
+
10
+ context 'when no spec_opts' do
11
+ let(:spec_opts) { nil }
12
+
13
+ it 'returns no spec_opts' do
14
+ expect(subject).to be nil
15
+ end
16
+ end
17
+
18
+ context 'when spec_opts have Knapsack Pro formatters' do
19
+ let(:spec_opts) { '--color --format d --format KnapsackPro::Formatters::TimeTracker' }
20
+
21
+ it 'returns spec_opts' do
22
+ expect(subject).to eq spec_opts
23
+ end
24
+ end
25
+
26
+ context 'when spec_opts have no Knapsack Pro formatters' do
27
+ let(:spec_opts) { '--color --format d' }
28
+
29
+ it 'returns spec_opts with added Knapsack Pro formatters' do
30
+ expect(subject).to eq '--color --format d --format KnapsackPro::Formatters::TimeTracker'
31
+ end
32
+ end
33
+ end
34
+
35
+ describe '#error_exit_code' do
36
+ subject { rspec_pure.error_exit_code(rspec_error_exit_code) }
37
+
38
+ context 'when RSpec has no defined error exit code' do
39
+ let(:rspec_error_exit_code) { nil }
40
+
41
+ it 'returns 1 as the default exit code' do
42
+ expect(subject).to eq 1
43
+ end
44
+ end
45
+
46
+ context 'when RSpec has a defined error exit code' do
47
+ let(:rspec_error_exit_code) { 2 }
48
+
49
+ it 'returns the custom exit code' do
50
+ expect(subject).to eq rspec_error_exit_code
51
+ end
52
+ end
53
+ end
54
+
55
+ describe '#args_with_seed_option_added_when_viable' do
56
+ let(:order_option) { KnapsackPro::Adapters::RSpecAdapter.order_option(args) }
57
+
58
+ subject { rspec_pure.args_with_seed_option_added_when_viable(order_option, seed, args) }
59
+
60
+ context 'when the order option is not random' do
61
+ let(:args) { ['--order', 'defined'] }
62
+ let(:seed) { KnapsackPro::Extensions::RSpecExtension::Seed.new(value: nil, used?: false) }
63
+
64
+ it 'does not add the seed option to args' do
65
+ expect(subject).to eq ['--order', 'defined']
66
+ end
67
+ end
68
+
69
+ ['random', 'rand'].each do |random_option_value|
70
+ context "when the order option is `#{random_option_value}`" do
71
+ let(:args) { ['--order', random_option_value] }
72
+
73
+ context 'when the seed is not used' do
74
+ let(:seed) { KnapsackPro::Extensions::RSpecExtension::Seed.new(value: '123', used?: false) }
75
+
76
+ it 'does not add the seed option to args' do
77
+ expect(subject).to eq ['--order', random_option_value]
78
+ end
79
+ end
80
+
81
+ context 'when the seed is used' do
82
+ let(:seed) { KnapsackPro::Extensions::RSpecExtension::Seed.new(value: '123', used?: true) }
83
+
84
+ it 'adds the seed option to args' do
85
+ expect(subject).to eq ['--order', random_option_value, '--seed', '123']
86
+ end
87
+ end
88
+ end
89
+ end
90
+
91
+ context 'when the order option is `rand:123`' do
92
+ let(:args) { ['--order', 'rand:123'] }
93
+ let(:seed) { KnapsackPro::Extensions::RSpecExtension::Seed.new(value: '123', used?: true) }
94
+
95
+ it 'does not add the seed option to args' do
96
+ expect(subject).to eq ['--order', 'rand:123']
97
+ end
98
+ end
99
+
100
+ context 'when the order option is not set in args AND seed is used' do
101
+ let(:args) { ['--format', 'documentation'] }
102
+ let(:seed) { KnapsackPro::Extensions::RSpecExtension::Seed.new(value: '123', used?: true) }
103
+
104
+ it 'adds the seed option to args' do
105
+ expect(subject).to eq ['--format', 'documentation', '--seed', '123']
106
+ end
107
+ end
108
+
109
+ context 'when the order option is not set in args AND seed is not used' do
110
+ let(:args) { ['--format', 'documentation'] }
111
+ let(:seed) { KnapsackPro::Extensions::RSpecExtension::Seed.new(value: '123', used?: false) }
112
+
113
+ it 'does not add the seed option to args' do
114
+ expect(subject).to eq ['--format', 'documentation']
115
+ end
116
+ end
117
+ end
118
+
119
+ describe '#prepare_cli_args' do
120
+ subject { rspec_pure.prepare_cli_args(args, has_format_option, has_require_rails_helper_option, rails_helper_exists, test_dir) }
121
+
122
+ context 'when no args' do
123
+ let(:args) { nil }
124
+ let(:has_format_option) { false }
125
+ let(:has_require_rails_helper_option) { false }
126
+ let(:test_dir) { 'spec' }
127
+
128
+ context 'when rails_helper does not exist' do
129
+ let(:rails_helper_exists) { false }
130
+
131
+ it 'adds the default progress formatter, the default path and the time tracker formatter, does not add require rails_helper' do
132
+ expect(subject).to eq [
133
+ '--format', 'progress',
134
+ '--default-path', 'spec',
135
+ '--format', 'KnapsackPro::Formatters::TimeTracker',
136
+ ]
137
+ end
138
+ end
139
+
140
+ context 'when rails_helper exists' do
141
+ let(:rails_helper_exists) { true }
142
+
143
+ it 'adds the default progress formatter, require rails_helper, the default path and the time tracker formatter' do
144
+ expect(subject).to eq [
145
+ '--format', 'progress',
146
+ '--require', 'rails_helper',
147
+ '--default-path', 'spec',
148
+ '--format', 'KnapsackPro::Formatters::TimeTracker',
149
+ ]
150
+ end
151
+ end
152
+ end
153
+
154
+ context 'when args are present and a custom test directory is set' do
155
+ let(:args) { '--color --profile --require rails_helper' }
156
+ let(:has_format_option) { false }
157
+ let(:has_require_rails_helper_option) { true }
158
+ let(:rails_helper_exists) { true }
159
+ let(:test_dir) { 'custom_spec_dir' }
160
+
161
+ it do
162
+ expect(subject).to eq [
163
+ '--color',
164
+ '--profile',
165
+ '--require', 'rails_helper',
166
+ '--format', 'progress',
167
+ '--default-path', 'custom_spec_dir',
168
+ '--format', 'KnapsackPro::Formatters::TimeTracker',
169
+ ]
170
+ end
171
+ end
172
+
173
+ context 'when args are present and has format option' do
174
+ let(:args) { '--color --profile --format d --require rails_helper' }
175
+ let(:has_format_option) { true }
176
+ let(:has_require_rails_helper_option) { true }
177
+ let(:rails_helper_exists) { true }
178
+ let(:test_dir) { 'spec' }
179
+
180
+ it 'uses the format option from args instead of the default formatter' do
181
+ expect(subject).to eq [
182
+ '--color',
183
+ '--profile',
184
+ '--format', 'd',
185
+ '--require', 'rails_helper',
186
+ '--default-path', 'spec',
187
+ '--format', 'KnapsackPro::Formatters::TimeTracker',
188
+ ]
189
+ end
190
+ end
191
+ end
192
+
193
+ describe '#rspec_command' do
194
+ let(:args) { ['--format', 'documentation'] }
195
+ let(:test_file_paths) { ['a_spec.rb', 'b_spec.rb'] }
196
+
197
+ subject { rspec_pure.rspec_command(args, test_file_paths, scope) }
198
+
199
+ context 'when there are no test file paths' do
200
+ let(:scope) { :queue_finished }
201
+ let(:test_file_paths) { [] }
202
+
203
+ it 'returns no messages' do
204
+ expect(subject).to eq []
205
+ end
206
+ end
207
+
208
+ context 'when a subset of queue (a batch of tests fetched from the Queue API)' do
209
+ let(:scope) { :batch_finished }
210
+
211
+ it 'returns messages with the RSpec command' do
212
+ expect(subject).to eq([
213
+ 'To retry the last batch of tests fetched from the Queue API, please run the following command on your machine:',
214
+ 'bundle exec rspec --format documentation "a_spec.rb" "b_spec.rb"',
215
+ ])
216
+ end
217
+ end
218
+
219
+ context 'when all tests fetched from the Queue API' do
220
+ let(:scope) { :queue_finished }
221
+
222
+ it 'returns messages with the RSpec command' do
223
+ expect(subject).to eq([
224
+ 'To retry all the tests assigned to this CI node, please run the following command on your machine:',
225
+ 'bundle exec rspec --format documentation "a_spec.rb" "b_spec.rb"',
226
+ ])
227
+ end
228
+ end
229
+
230
+ describe '#exit_summary' do
231
+ subject { rspec_pure.exit_summary(unexecuted_test_files) }
232
+
233
+ context 'when there are no unexecuted test files' do
234
+ let(:unexecuted_test_files) { [] }
235
+
236
+ it { expect(subject).to be_nil }
237
+ end
238
+
239
+ context 'when there are unexecuted test files' do
240
+ let(:unexecuted_test_files) { ['b_spec.rb', 'c_spec.rb'] }
241
+
242
+ it 'returns a warning message' do
243
+ expect(subject).to eq 'Unexecuted tests on this CI node (including pending tests): b_spec.rb c_spec.rb'
244
+ end
245
+ end
246
+ end
247
+ end
248
+ end