Skip to content
This repository was archived by the owner on Nov 30, 2024. It is now read-only.

Allow ordering specs by modification time #2778

Merged
merged 8 commits into from
Dec 25, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions features/command_line/order.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,10 @@ order of groups at each level is randomized.

With `rand` you can also specify a seed.

Use `recently-modified` to run the most recently modified files first. You can
combine it with `--only-failures` to find the most recent failing specs. Note
that `recently-modified` and `rand` are mutually exclusive.

## Example usage

The `defined` option is only necessary when you have `--order rand` stored in a
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unrelated, but this statement seems to be contradictive to the default ordering setting from the project initializer:

config.order = :random

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thats not the default, defined is the default, but the convention overrides it, but this sentence is slightly misleading I agree.

Expand All @@ -22,4 +26,5 @@ config file (e.g. `.rspec`) and you want to override it from the command line.
--order rand
--order rand:123
--seed 123 # same as --order rand:123
--order recently-modified
</code></pre>
9 changes: 5 additions & 4 deletions lib/rspec/core/option_parser.rb
Original file line number Diff line number Diff line change
Expand Up @@ -58,10 +58,11 @@ def parser(options)
end

parser.on('--order TYPE[:SEED]', 'Run examples by the specified order type.',
' [defined] examples and groups are run in the order they are defined',
' [rand] randomize the order of groups and examples',
' [random] alias for rand',
' [random:SEED] e.g. --order random:123') do |o|
' [defined] examples and groups are run in the order they are defined',
' [rand] randomize the order of groups and examples',
' [random] alias for rand',
' [random:SEED] e.g. --order random:123',
' [recently-modified] run the most recently modified files first') do |o|
options[:order] = o
end

Expand Down
13 changes: 12 additions & 1 deletion lib/rspec/core/ordering.rb
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,14 @@ def jenkins_hash_digest(string)
MAX_32_BIT = 4_294_967_295
end

# @private
# Orders items by modification time (most recent modified first).
class RecentlyModified
def order(list)
list.sort_by { |item| -File.mtime(item.metadata[:absolute_file_path]).to_i }
end
end

# @private
# Orders items based on a custom block.
class Custom
Expand All @@ -77,7 +85,8 @@ def initialize(configuration)
@configuration = configuration
@strategies = {}

register(:random, Random.new(configuration))
register(:random, Random.new(configuration))
register(:recently_modified, RecentlyModified.new)

identity = Identity.new
register(:defined, identity)
Expand Down Expand Up @@ -132,6 +141,8 @@ def order=(type)
:random
elsif order == 'defined'
:defined
elsif order == 'recently-modified'
:recently_modified
end

register_ordering(:global, ordering_registry.fetch(ordering_name)) if ordering_name
Expand Down
11 changes: 11 additions & 0 deletions spec/integration/order_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,17 @@
end
end

describe '--order rand --order recently-modified' do
it 'overrides random ordering with recently-modified option' do
2.times { run_command 'spec/order_spec.rb --order rand --order recently-modified -f doc' }

expect(stdout.string).not_to match(/Randomized with seed/)

top_level_groups { |first_run, second_run| expect(first_run).to eq(second_run) }
nested_groups { |first_run, second_run| expect(first_run).to eq(second_run) }
end
end

describe '--order defined on CLI with --order rand in .rspec' do
after { remove '.rspec' }

Expand Down
15 changes: 15 additions & 0 deletions spec/rspec/core/ordering_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,21 @@ def order_with(seed)
end
end

RSpec.describe RecentlyModified do
before do
allow(File).to receive(:mtime).with('./file_1.rb').and_return(::Time.new)
allow(File).to receive(:mtime).with('./file_2.rb').and_return(::Time.new + 1)
end

it 'orders list by file modification time' do
file_1 = instance_double(Example, :metadata => { :absolute_file_path => './file_1.rb' })
file_2 = instance_double(Example, :metadata => { :absolute_file_path => './file_2.rb' })
strategy = RecentlyModified.new

expect(strategy.order([file_1, file_2])).to eq([file_2, file_1])
end
end

RSpec.describe Custom do
it 'uses the block to order the list' do
strategy = Custom.new(proc { |list| list.reverse })
Expand Down