Skip to content

Commit

Permalink
Add --single-process-tag option to run specific Cucumber/Gherkin scen…
Browse files Browse the repository at this point in the history
…arios sequentially
  • Loading branch information
andrii-rymar committed Apr 10, 2021
1 parent 9bc9233 commit a5a01bd
Show file tree
Hide file tree
Showing 3 changed files with 53 additions and 12 deletions.
6 changes: 5 additions & 1 deletion lib/parallel_tests/cli.rb
Expand Up @@ -208,7 +208,11 @@ def parse_options!(argv)
(options[:single_process] ||= []) << /#{pattern}/
end

opts.on("-i", "--isolate", "Do not run any other tests in the group used by --single(-s)") do
opts.on("--single-tag [TAG]", "Run all Cucumber/Gherkin scenarios with specified tag in the same process") do |tag|
options[:single_process_tag] = tag
end

opts.on("-i", "--isolate", "Do not run any other tests in the group used by --single(-s) or --single-tag") do
options[:isolate] = true
end

Expand Down
4 changes: 2 additions & 2 deletions lib/parallel_tests/cucumber/scenario_line_logger.rb
Expand Up @@ -21,7 +21,7 @@ def visit_feature_element(uri, feature_element, feature_tags, line_numbers: [])
# or if it is not at the correct location
return if line_numbers.any? && !line_numbers.include?(test_line)

@scenarios << [uri, feature_element.source_line].join(":")
@scenarios << [[uri, feature_element.source_line].join(":"), scenario_tags]
else # :ScenarioOutline
feature_element.examples.each do |example|
example_tags = example.tags.map(&:name)
Expand All @@ -31,7 +31,7 @@ def visit_feature_element(uri, feature_element, feature_tags, line_numbers: [])
test_line = row.source_line
next if line_numbers.any? && !line_numbers.include?(test_line)

@scenarios << [uri, test_line].join(':')
@scenarios << [[uri, test_line].join(':'), scenario_tags]
end
end
end
Expand Down
55 changes: 46 additions & 9 deletions lib/parallel_tests/grouper.rb
@@ -1,6 +1,8 @@
# frozen_string_literal: true
module ParallelTests
class Grouper
BY_SCENARIOS_SUPPORTED_OPTIONS = [:single_process_tag].freeze

class << self
def by_steps(tests, num_groups, options)
features_with_steps = group_by_features_with_steps(tests, options)
Expand All @@ -9,20 +11,16 @@ def by_steps(tests, num_groups, options)

def by_scenarios(tests, num_groups, options = {})
scenarios = group_by_scenarios(tests, options)
in_even_groups_by_size(scenarios, num_groups)
in_even_groups_by_size(scenarios, num_groups, options.slice(BY_SCENARIOS_SUPPORTED_OPTIONS))
end

def in_even_groups_by_size(items, num_groups, options = {})
groups = Array.new(num_groups) { { items: [], size: 0 } }

return specify_groups(items, num_groups, options, groups) if options[:specify_groups]

# add all files that should run in a single process to one group
single_process_patterns = options[:single_process] || []

single_items, items = items.partition do |item, _size|
single_process_patterns.any? { |pattern| item =~ pattern }
end
# add all files/scenarios that should run in a single process to one group
single_items, items = separate_single_items(items, options)

isolate_count = isolate_count(options)

Expand All @@ -41,7 +39,7 @@ def in_even_groups_by_size(items, num_groups, options = {})
group_features_by_size(items_to_group(items), groups[isolate_count..-1])
else
# add all files that should run in a single non-isolated process to first group
single_items.each { |item, size| add_to_group(groups.first, item, size) }
group_features_by_size(items_to_group(single_items), [groups.first])

# group all by size
group_features_by_size(items_to_group(items), groups)
Expand Down Expand Up @@ -129,6 +127,22 @@ def group_by_scenarios(tests, options = {})
ParallelTests::Cucumber::Scenarios.all(tests, options)
end

def separate_single_items(items, options)
items.partition { |item, _size| to_single_items?(item, options) }
end

def to_single_items?(item, options)
if options[:single_process]
options[:single_process].any? { |pattern| item =~ pattern }
elsif options[:single_process_tag]
raise "--single-tag option can be used only with '--group-by scenarios'" unless item_with_tags?(item)
item_tags = item[1]
item_tags.any? { |tag| tag.match?(options[:single_process_tag]) }
else
false
end
end

def group_features_by_size(items, groups_to_fill)
items.each do |item, size|
size ||= 1
Expand All @@ -138,7 +152,30 @@ def group_features_by_size(items, groups_to_fill)
end

def items_to_group(items)
items.first && items.first.size == 2 ? largest_first(items) : items
return items_without_tags(items) if items_with_tags?(items)
return largest_first(items) if items_with_size?(items)

items
end

def items_with_tags?(items)
items.first.is_a?(Array) && item_with_tags?(items.first)
end

def items_with_size?(items)
items.first.is_a?(Array) && item_with_size?(items.first)
end

def item_with_tags?(item)
item[1].is_a?(Array)
end

def item_with_size?(item)
item[1].is_a?(Numeric)
end

def items_without_tags(items)
items.map(&:first)
end
end
end
Expand Down

0 comments on commit a5a01bd

Please sign in to comment.