class RuboCop::Cop::RSpec::FilePath
Checks that spec file paths are consistent and well-formed.
By default, this checks that spec file paths are consistent with the test subject and and enforces that it reflects the described class/module and its optionally called out method.
With the configuration option `IgnoreMethods` the called out method will be ignored when determining the enforced path.
With the configuration option `CustomTransform` modules or classes can be specified that should not as usual be transformed from CamelCase to snake_case (e.g. 'RuboCop' => 'rubocop' ).
With the configuration option `SpecSuffixOnly` test files will only be checked to ensure they end in '_spec.rb'. This option disables checking for consistency in the test subject or test methods.
@example
# bad whatever_spec.rb # describe MyClass # bad my_class_spec.rb # describe MyClass, '#method' # good my_class_spec.rb # describe MyClass # good my_class_method_spec.rb # describe MyClass, '#method' # good my_class/method_spec.rb # describe MyClass, '#method'
@example when configuration is `IgnoreMethods: true`
# bad whatever_spec.rb # describe MyClass # good my_class_spec.rb # describe MyClass # good my_class_spec.rb # describe MyClass, '#method'
@example when configuration is `SpecSuffixOnly: true`
# good whatever_spec.rb # describe MyClass # good my_class_spec.rb # describe MyClass # good my_class_spec.rb # describe MyClass, '#method'
Constants
- MSG
Public Instance Methods
# File lib/rubocop/cop/rspec/file_path.rb, line 74 def on_top_level_example_group(node) return unless top_level_groups.one? example_group(node) do |send_node, example_group, arguments| next if routing_spec?(arguments) ensure_correct_file_path(send_node, example_group, arguments) end end
Private Instance Methods
# File lib/rubocop/cop/rspec/file_path.rb, line 132 def camel_to_snake_case(string) string .gsub(/([^A-Z])([A-Z]+)/, '\1_\2') .gsub(/([A-Z])([A-Z][^A-Z\d]+)/, '\1_\2') .downcase end
# File lib/rubocop/cop/rspec/file_path.rb, line 139 def custom_transform cop_config.fetch('CustomTransform', {}) end
# File lib/rubocop/cop/rspec/file_path.rb, line 86 def ensure_correct_file_path(send_node, example_group, arguments) pattern = pattern_for(example_group, arguments.first) return if filename_ends_with?(pattern) # For the suffix shown in the offense message, modify the regular # expression pattern to resemble a glob pattern for clearer error # messages. offense_suffix = pattern.gsub('.*', '*').sub('[^/]', '') .sub('\.', '.') add_offense(send_node, message: format(MSG, suffix: offense_suffix)) end
# File lib/rubocop/cop/rspec/file_path.rb, line 124 def expected_path(constant) File.join( constant.const_name.split('::').map do |name| custom_transform.fetch(name) { camel_to_snake_case(name) } end ) end
# File lib/rubocop/cop/rspec/file_path.rb, line 147 def filename_ends_with?(pattern) filename = File.expand_path(processed_source.buffer.name) filename.match?("#{pattern}$") end
# File lib/rubocop/cop/rspec/file_path.rb, line 143 def ignore_methods? cop_config['IgnoreMethods'] end
# File lib/rubocop/cop/rspec/file_path.rb, line 118 def name_pattern(method_name) return unless method_name&.str_type? ".*#{method_name.str_content.gsub(/\W/, '')}" unless ignore_methods? end
# File lib/rubocop/cop/rspec/file_path.rb, line 102 def pattern_for(example_group, method_name) if spec_suffix_only? || !example_group.const_type? return pattern_for_spec_suffix_only? end [ expected_path(example_group), name_pattern(method_name), '[^/]*_spec\.rb' ].join end
# File lib/rubocop/cop/rspec/file_path.rb, line 114 def pattern_for_spec_suffix_only? '.*_spec\.rb' end
# File lib/rubocop/cop/rspec/file_path.rb, line 152 def relevant_rubocop_rspec_file?(_file) true end
# File lib/rubocop/cop/rspec/file_path.rb, line 98 def routing_spec?(args) args.any?(&method(:routing_metadata?)) end
# File lib/rubocop/cop/rspec/file_path.rb, line 156 def spec_suffix_only? cop_config['SpecSuffixOnly'] end